1

I have a few React components that need exactly two of three props to represent a time range: from, to, or duration. Any combination of two is enough to derive the third one correctly. So I want TypeScript to enforce that exactly two of these props is required.

I tried defining props like this:

type RangeProps =
  | {
      from: Date
      to: Date
    }
  | {
      from: Date
      duration: number
    }
  | {
      duration: number
      to: Date
    }

But when I supply all three props (<Range from={startDate} duration={duration} to={endDate} />, TypeScript doesn't complain. How can I get it to complain?

callum
  • 34,206
  • 35
  • 106
  • 163
  • https://dev.to/maissenayed/conditional-react-props-with-typescript-43lg I think you can apply this solution for `trom,to,duration`? – Yilmaz Jun 06 '23 at 00:58
  • The non-combinatorial-complexity way to do it is to add a new `kind` key to each, and give each `kind` a unique number of string value: `type RangeProps = | { kind: 1, from: Date, to: Date } | { kind: 2, from: Date, duration: number }` – Craig Hicks Jun 06 '23 at 01:13
  • Please see [this](https://tsplay.dev/NaDXpw) example. Also see [this](https://stackoverflow.com/questions/65805600/type-union-not-checking-for-excess-properties#answer-65805753) answer for more information – captain-yossarian from Ukraine Jun 06 '23 at 07:28

2 Answers2

2

You can use the type never, this type means that the property cannot be passed:

type RangeProps =
  | {
      from: Date;
      to: Date;
      duration?: never;
    }
  | {
      from: Date;
      duration: number;
      to?: never;
    }
  | {
      duration: number;
      to: Date;
      from?: never;
    };
Paulo Fernando
  • 3,148
  • 3
  • 5
  • 21
  • [While this code may be the solution, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.](https://meta.stackoverflow.com/a/260413/2887218) – jcalz Jun 06 '23 at 02:38
1

enter image description here playground

use this generic trick T extends never? T : some type check logic

T extends any? some type check logic : never also work

Acid Coder
  • 2,047
  • 15
  • 21