Dynamically resolve property type based on another property value in TypeScript

It's a bit late but I hope it helps others like it helped me.

Discriminated unions, also known as tagged unions or algebraic data types can be used to solve this problem.

interface MultipleSelectProps {
    isMultiple: true;
    options: string[];
    value: string[];
    onChange: (value: string[]) => void;
}

interface SingleSelectProps {
    isMultiple: false;
    options: string[];
    value: string;
    onChange: (value: string) => void;
}

type SelectProps = MultipleSelectProps | SingleSelectProps;

Usage example:

function Select(props: SelectProps) {
    if (props.isMultiple) {
        const { value, onChange } = props;
        onChange(value);
    } else if (props.isMultiple === false) {
        const { value, onChange } = props;
        onChange(value);
    }
}

Note: When isMultiple is undefined or null it is not possible to infer the specific type of SelectProps. In these cases is necessary to do a strict comparison isMultiple === false.

Source: https://blog.mariusschulz.com/2016/11/03/typescript-2-0-tagged-union-types


You can make use of typescript Distributive Conditional Types https://www.typescriptlang.org/docs/handbook/2/conditional-types.html

So your type will look like this:

type SelectProps<TMultiple = boolean> = TMultiple extends true
  ? {
      isMultiple: TMultiple;
      options: string[];
      value: string[];
      onChange: (value: string[]) => void;
    }
  : {
      isMultiple: TMultiple;
      options: string[];
      value: string;
      onChange: (value: string) => void;
    };

Here is a quick example: https://stackblitz.com/edit/typescript-9jgvys

Tags:

Typescript