0

I have made a component MyComponent with react. I would like to define the props for this component.

Usually i do it like

type Props = {
  foo: string
}

const MyComponent = (props: Props) => ...

Here are the props i would like to always be available

selected: string <-- required
onSelect(): void <-- required
margin?: string <-- optional

And the following are two sets that are non-compatible, ie. only one of them can be used.

Set one:

compact?: boolean <-- optional
minWidth?: number <-- optional
maxWidth?: number <-- optional

Set two:

width?: number <-- optional

What is the best way to define these props so that it makes the most sense to the developer using the component? I.e, what gives the best intellisense experience?

johann1301s
  • 343
  • 4
  • 19
  • Maybe dupe of https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types – kelsny Nov 05 '22 at 15:12

1 Answers1

2

You can create a XOR-like behavior by using never:

type Props = {
    selected: string;
    onSelect(): void;
    margin?: string;
} & (
    | {
          compact?: boolean;
          minWidth?: number;
          maxWidth?: number;
          width?: never;
      }
    | {
          compact?: never;
          minWidth?: never;
          maxWidth?: never;
          width?: number;
      }
);

Then when you give it invalid props:

<MyComponent selected="foo" onSelect={() => {}} margin="0" width={0} compact={true} />

You'll get a fairly helpful error:

Type '{ selected: string; onSelect: () => void; margin: string; width: number; compact: true; }' is not assignable to type 'IntrinsicAttributes & Props'. Type '{ selected: string; onSelect: () => void; margin: string; width: number; compact: true; }' is not assignable to type '{ compact?: undefined; minWidth?: undefined; maxWidth?: undefined; width?: number | undefined; }'. Types of property 'compact' are incompatible. Type 'true' is not assignable to type 'undefined'.(2322)

Playground

kelsny
  • 23,009
  • 3
  • 19
  • 48