Home > Software design >  Typescript: How to use an array of options as a type for another prop
Typescript: How to use an array of options as a type for another prop

Time:02-04

I am trying to find a way to enforce a type of a prop by using the values of another prop.

The list of array options could be anything set when the component is used, so I can't manually type the options. Is this even possible?

// Props
export interface Props {
  options: string[]; // These will be the options
  selected: string; // Enforce this to be one the options
}

// Component
const Component = ({ options, selected }: Props) => {
  ...
  return <div>{selected}</div>;
};

// Usage of component somewhere else
<Component
  options={['2020', '2021', '2022', '2023']}
  selected="1999" // <--- This should return an error
/>

I did attempt to use generics but I am fairly new to Typescript and failed :(

CodePudding user response:

  1. Define options as a tuple using the spread operator. This allows to use the strings array as a list of literal types.
  2. Use number to index the array and create a constraint for the selected prop (a union of all the array values).
// Props
export interface Props<T extends string[]> {
  options: [...T]; // These will be the options
  selected: T[number]; // Enforce this to be one the options
}

// Component
const Component = <T extends string[]>(props: Props<T>) => {
  return <div>{props.selected}</div>;
};

// Usage of component somewhere else
<Component
  options={['2020', '2021', '2022', '2023']}
  selected="1999"
></Component>

Typescript playground.

CodePudding user response:

Conceptually you need Props to be generic in the union of string literal types of the options array elements:

interface Props<T extends string> {
  options: T[];
  selected: T
}

A wrinkle is that in your component, the compiler will happily infer T from both the options and the selected properties, preventing your desired error from happening:

const Component = <T extends string>({ options, selected }: Props<T>) => {
  return <div>{selected}</div>;
};

<Component
  options={['2020', '2021', '2022', '2023']}
  selected="2019" // no error
></Component>
// Props<"2020" | "2021" | "2022" | "2023" | "2019"> inferred            
  • Related