Typescript: How to use a union in an interface correctly?

Viewed 40

This should have been simple but, when defining an interface with options type:

  options:
     Array<{
        title?: string;
        options: Option[];
      }>
    | Option[];

I'm using map function to loop over the array, something like this:

  {options.map((option) => (
              <SelectPrimitive.Group key={option.title}>

Then I won't be able to access option.title, ts will say this title property doesn't exist. But the moment I remove the second part of the union:

options:
     Array<{
        title?: string;
        options: Option[];
      }>

It will work. Why doesn't ts understand that it's a union type, and instead it selects the second part of the union?

2 Answers

It actually understands that's a union type.

When using a union type A | B it means that the object can be of type A or type B. TS will do type checking taking into account both A and B. Common properties will work, but if a property is only on one type you need to narrow the type.

That's where your error is coming from.

To answer your question about "how to do is how to check the type of the prop in real time", you can simply check with a if statement if the object option in the map, is an instance of Option. You could also just check the type of the first element in options before your map.

Example 1

options.map((option) => (
    if (option instanceof Option) {
        <SelectPrimitive.Group key={option.title}>
    }

...

Example 2

if (options.length !== 0 && options[0] instanceof Option) {
    options.map((option) => (
          <SelectPrimitive.Group key={option.title}>
          ...
}
Related