Home > Back-end >  define a prop type as a single number or array of numbers based on another prop
define a prop type as a single number or array of numbers based on another prop

Time:01-25

Here is a simple example of what I am looking for. I am implementing an array and I want to check if the multi prop is true, type of items should be number[]. Otherwise, set the type to number.

interface EnhancedSelectProps {
  items: multi ? number[] : number;
  multi?: boolean;
}

const EnhancedSelect = ({
  items,
  multi,
}: EnhancedSelectProps) => {}

I have tried the union type but it is not working. when I want to do something like this, it will give me a ts error.

interface EnhancedSelectProps {
  items?: number[] | number;
  multi?: boolean;
}

const EnhancedSelect = ({
  items,
  multi,
}: EnhancedSelectProps) => {
  if(multi) console.log(items.length);
    else console.log(items)
}

CodePudding user response:

Titian beat me to it but here is a version using generics

interface EnhancedSelectProps<T extends boolean> {
    items: T extends false ? number : number[];
    multi?: T;
}

function EnhancedSelect({
    items,
    multi,
}: EnhancedSelectProps<true> | EnhancedSelectProps<false>) {
    if (multi) console.log(items.length);
    else console.log(items)
}

Playground

CodePudding user response:

The simplest option is to use a discriminated union, discriminated on the multi field:

type EnhancedSelectProps = {
  items?: number[];
  multi: true;
} | {
  multi: false; 
  items?: number;
}

const EnhancedSelect = ({
  items,
  multi,
}: EnhancedSelectProps) => {
  if(multi) console.log(items?.length);
    else console.log(items)
}
EnhancedSelect({ multi: true, items: [1,2]})
EnhancedSelect({ multi: true, items: 1}) // error
EnhancedSelect({ multi: false, items: [1,2]}) // error
EnhancedSelect({ multi: false, items: 1}) 
EnhancedSelect({ items: [1,2]}) // error
EnhancedSelect({ items: 1 }) 

Playground Link

If you are using an older version of Typescript (<= 4.6), you can't destructure the parameter and still have TS understand the relationship between the fields, you will need to wither use the parameter itself or destructure after the check:


const EnhancedSelect = (p: EnhancedSelectProps) => {
  if(p.multi) {
    console.log(p.items?.length);
    const { items } = p
    console.log(items?.length);
  } else {
    console.log(p.items)
    const { items } = p
    console.log(items)
  }
}

Playground Link

  • Related