Steven Petryk
Steven Petryk

Reputation: 683

TypeScript: how to only allow certain combinations of keys in object?

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

Answers (2)

tenshi
tenshi

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>

Playground


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

lucki
lucki

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

Related Questions