In typescript: is it possible to check if type expected type IS NOT some type? Or create an interface that defines methods/props that should not be there?
In the TypeScript compiler it is not yet possible to do this, though it might be possible eventually.
This issue on the TypeScript project seems to be the main one tracking this feature request; many other similar issues are linked to it.
It is as always possible to do these checks at runtime. This can be done manually via standard checks/assertions. I personally like using JSONSchema for non-trivial "everything except objects shaped like X" cases, or the io-ts package, to build these types of runtime validators. In TypeScript, you also have access to type guard functions, which can be used to perform these validations.
EDIT this is possible in a limited, not very useful way. Using a modification of the Omit type from this article the type checker can be made to reject some, but not all, violating types.
For example, let's say you wanted a type for "any object that does not have properties c or d". You could express that type thus:
type Diff = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];
type Omit = Pick>;
type AnyTypeWithoutCorD = Omit
Using that type, the following is rejected by the typechecker:
type MyType = { a: number, b: number, c: number };
// Accepts a generic argument and a parameter; ensures the
// parameter can be constrained into the AnyTypeWithoutCorD type.
function funcGeneric(arg: AnyTypeWithoutCorD) {}
// Accepts a parameter of a known type MyType, constrained
// into the AnyTypeWithoutCorD type.
function func(arg: AnyTypeWithoutCorD) {}
let foo: AnyTypeWithoutCorD = { a: 1, b: 1, c: 2 } // Error: type not assignable
func({ a: 1, b: 1, c: 2 }) // Error: type not assignable
funcGeneric({ a: 1, b: 1, c: 2 }) // Error: type not assignable
Restrictions:
MyType in the example) must be explicitly enumerated. No index property signatures are allowed; those cause the typechecker to accept Omit objects regardless of their fields. For example, if you add [x: string]: any into the specification of MyType in the above example, the typechecker happily accepts all of the arguments ( & { [x: string]: any } is equivalent and behaves the same way). If you're performing Omit-type validation on things whose input types you don't control, this means that your validation won't take place if any input types have index property signatures.Omit type constructor, or doing something equivalently "early" on in type checking. Supplying data from a previous assignment, or via type assertion does not perform the Omit validation as expected.Omit type, and you do not explicitly state the generic when calling the function, it will not be correctly inferred, and as a result Omit validation will not occur since your type will not pass.For example, none of the below work (they are all accepted by the type checker):
let bar: MyType = { a: 1, b: 1, c: 2 }
func(bar)
func({ a: 1, b: 1, c: 2 } as MyType)
funcGeneric(bar)
funcGeneric({ a: 1, b: 1, c: 2 })
let ok: AnyTypeWithoutCorD
These are my first attempts at achieving/demonstrating this, so folks more knowledgeable about TypeScript and custom type construction may correct me. Take it with a grain of salt.
Conclusions:
The Omit solution is not worth it.
Unless you control all input types to your Omit receivers, and are maintain discipline in keeping those input types free of index property signatures, and also ensure that every time you supply anything to one of those receivers it is actually picking up the Omit constraint, this will do more harm than good.
This is because it will sometimes correctly validate your types, which creates a false sense of security and difficult-to-debug, seemingly inconsistent behavior.
The issue linked in the very first part of the question, if completed, will result in a much more robust, predictable, and documented solution for this use case. Until then, use runtime checks.