Search code examples
reactjstypescripttypesconditional-statementsunion

Typescript - the type of property that depends on another optional property


I have a component in React

const Faq = ({ shortVersion, data }: FaqProps) => { }

With defined types


type FaqProps =
  | {
      shortVersion: true;
      data: ShortFaqData[];
    }
  | {
      shortVersion: false;
      data: ExtendedFaqData[];
    };

And it works

const testDataShort: ShortFaqData[]
const testDataExtended: ExtendedFaqData[]
<Faq shortVersion={false} data={testDataExtended} />
<Faq shortVersion data={testDataShort} />

But I would like shortVersion not to have to be false, but could also be optional

so I tried this

type FaqProps =
  | {
      shortVersion: true;
      data: ShortFaqData[];
    }
  | {
      shortVersion?: false;
      data: ExtendedFaqData[];
    };

And this

type FaqProps =
  | {
      shortVersion: true;
      data: ShortFaqData[];
    }
  | {
      shortVersion: false | undefined;
      data: ExtendedFaqData[];
    };

And it not work for case without shortVersion (it works when i pass shortVersion)

case with passed shortVersion

case without passed shortVersion

Is it possible to make the IDE suggest the correct type for data?


Solution

  • It is, with overloads. Here's my simplified version of your real-world problem:

    type Props = {
        flag: true;
        data: number;
    } | {
        flag?: false;
        data: string;
    };
    

    Normally, you would have something like this:

    function Comp(props: Props) {
    

    With overloads to describe the props (instead of relying on discriminated unions):

    function Comp(props: { flag?: false; data: string }): JSX.Element;
    function Comp(props: { flag: true; data: number }): JSX.Element;
    function Comp(props: Props) {
    

    And now you'll get the correctly suggested type:

    <Comp data={} />; // hover over 'data' - it's shown as `string`!
    

    However, I don't think you should rely on this workaround. Instead you should just bring this problem up to the maintainers as an issue and get it fixed. This behavior is obviously not ideal and should be corrected. I can't really think of a reason why this would be the desired behavior.

    Hopefully you can apply this example to your real-world problem.

    Playground