Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically resolve property type based on another property value in TypeScript

Tags:

typescript

I have the following TypeScript interface:

interface SelectProps {     options: Option[];     value: string[];     onChange: (value: string[]) => void; } 

I want to add boolean called isMultiple that will change the types of the other properties.

When isMultiple=true

  • enforce value:string[]
  • enforce onChange: (value: string[]) => void;

When isMultiple=false

  • enforce value:string
  • enforce onChange: (value: string) => void;

Is it possible to dynamically set the type of other properties based on the value of one property?

like image 824
styfle Avatar asked Jan 17 '17 19:01

styfle


2 Answers

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

like image 115
Tito Nobre Avatar answered Oct 15 '22 10:10

Tito Nobre


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

like image 22
Cris Avatar answered Oct 15 '22 10:10

Cris