Typescript: Type To Contain Any Value Except Values From A Predefined Set
Solution 1:
Negated types are not currently supported in TypeScript as concrete types, but maybe they will be someday.
For now, the only way to express negated types is indirectly, via a generic type that verifies whether a condition is met.
Something like:
type DefinitelyNot<T, C> = [T] extends [C]
?Invalid<[C, "is prohibited because it might be", T]>
: [C] extends [T]
?Invalid<[C, "is prohibited because it is assignable to", T]>
: C;
The type DefinitelyNot<T, C>
takes a type T
to negate, and a candidate type C
. If we can be sure that C
is not compatible with T
, then we return C
itself. Otherwise, we return something that C
will not match, specifically an Invalid
type that causes an error. Well, we would do that if invalid types were supported, which they're currently not. So we need a workaround there too:
typeInvalid<Msg> = Msg & Error;
It makes for some fairly ugly error messages, but at least the developer might have some chance of figuring out why the error appeared. Then we can make a function which takes a type T
and produces a new function that only accepts arguments not compatible with T
:
const makeNot = <T>() => <C>(val: C & DefinitelyNot<T, C>): C => val;
Let's try it out:
typeFruit = "Apple" | "Banana" | "Orange";
const asNotFruit = makeNot<Fruit>();
const a = asNotFruit("Carrot"); // okayconst b = asNotFruit("Apple"); // error// ┌--------------> ~~~~~~~ // ["Apple", "is prohibited because it is assignable to", Fruit]functionsomeRandomFunction(x: string, y: number) {
const c = asNotFruit(x); // error// ┌---------------> ~// [string, "is prohibited because it might be", Fruit]const d = asNotFruit(y); // okay (a number cannot be Fruit)
}
As you can see, "Carrot"
and number
were accepted because those are definitely not Fruit
. "Apple"
was rejected because it definitely isFruit
, and string
was rejected because it might beFruit
.
Not sure if you want to use this sort of solution, but I figured I'd include it anyway. Hope that helps. Good luck!
Solution 2:
I would answer that this is definitely not possible with Typescript. There is no negation operator for sets in the language.
You can create an instanceOf typeguard though.
https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
type Fruit = "Apple" | "Orange";
function isFruit(fruit: string): fruit is Fruit {
return !(['Apple', 'Orange'].includes(fruit));
}
Post a Comment for "Typescript: Type To Contain Any Value Except Values From A Predefined Set"