Reputation: 683
In TypeScript, I'd like to define an object type that represents an inequality. Something like this:
{ "<": x => Math.sin(x) } // ok, y < sin(x)
{ ">": x => Math.sin(x) } // ok, y > sin(x)
{ ">=": -4, "<": 4 } // ok, -4 <= y < 4
But I want to prevent nonsensical combinations, like having both "less than" and "less than or equal to":
{ "<": 5, "<=": 5 } // should cause a TypeScript error
Is this possible? So far I've tried something that felt obvious: a union.
type Fn = number | ((x: number) => number)
type Inequality =
| Record<">", Fn>
| Record<"<", Fn>
| Record<"<=", Fn>
| Record<">=", Fn>
| Record<">" | "<", Fn>
| Record<">" | "<=", Fn>
| Record<">=" | "<", Fn>
| Record<">=" | "<=", Fn>
However, with this, TypeScript unions all these types together and allows any combination of these keys. Playground link.
Is it possible to make TypeScript only allow the combinations I declare?
Upvotes: 0
Views: 203
Reputation: 26307
Intersect the members of the union with another record that uses never
:
type Inequality =
| Record<">", Fn> & Record<">=", never>
| Record<"<", Fn> & Record<"<=", never>
| Record<"<=", Fn> & Record<"<", never>
| Record<">=", Fn> & Record<">", never>
| Record<">" | "<", Fn> & Record<">=" | "<=", never>
| Record<">" | "<=", Fn> & Record<">=" | "<", never>
| Record<">=" | "<", Fn> & Record<">" | "<=", never>
| Record<">=" | "<=", Fn> & Record<">" | "<", never>
For smaller cases this is alright, but it gets out of hand very quickly and you may need a utility type to generate this union for you from some rules (like ">" and ">=" are mutually exclusive).
You may find XOR types in TypeScript useful.
Upvotes: 2
Reputation: 1
You can define the type of the wrong inequalities and then infer if the current object is wrong ( implementation in the playground
But to be honest you'd be better doing some checks in a function , there are other runtime cases that cannot be covered, like for exemple {">": 4, ">=": 3}
is a valid inequality , or {">": 0, "<": -1}
is wrong inequality
Upvotes: 0