Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine TypeScript type of a possibly empty array

I need to figure out the TypeScript type of data coming into my React component. The data could represent one of two things, cats or dogs:

my-component.tsx:

export const MyComponent = { props: {
  data: any; // I wish I could use the union type "Cat[] | Dog[]" here
}}: JSX.Element => {
  ...

  return (
    <ComponentNotModifiableByMe
      data={props.data}
      // If "Cat[] | Dog[]" is used above, TS says "Type 'Dog[]' is not assignable to type 'Cat[]'. ts(2322)"
      // If "any" is used above, this works okay, but defeats the purpose of TypeScript
      ...
    />
  );
}

cat-stuff.tsx:

export type Cat = {
  foo: string;
  bar: string;
  address: string;
  birthday: string;
}

dog-stuff.tsx:

export type Dog = {
  bar: string;
  address: string;
  birthday: string;
}

There appear to be five ways to check what things are in TypeScript, based on an existing SO answer:

  1. instanceof

    N/A, this checks against classes, but I have types

  2. typeof

    N/A, this checks against primitive types, but I have custom TypeScript types

  3. in

    This would probably work if I had Cat | Dog. But I have arrays, and it's valid in my app for data to be an empty array. So, I can't rely on checking the first element of data, because it might not exist.

  4. user-defined type guard, AKA type predicates

    This seems the most promising, but as with #3, there might not be any actual data for me to check, so I don't know what I would put in an isCat() or isDog() function.

  5. discriminated union

    N/A, there is no kind property or equivalent on my types that is a unique identifier; adding one could be a workaround, but it might not work anyways, for the same reason as #3 and #4 above.

How can I figure out the type of data in a way that works for empty arrays? Currently I'm manually passing an extra prop to MyComponent but that doesn't feel like good coding practice. If there's a React way around this problem (instead of a TypeScript way), that'd be fine too.

like image 583
Anonica Avatar asked Jun 09 '26 16:06

Anonica


1 Answers

If the array is empty there is no possible way to infer its type, so your extra prop is required.

You could write something like this:

export const MyComponent = { props: {
  data: Cat[] | Dog[],
  cats: boolean,
  dogs: boolean,
}}: JSX.Element => {

  // After calling this function in a if, data will be typed as Cat[]
  isArrayOfCats(data: Cat[] | Dog[]): data is Cat[] {
    return cats;
  }

  // After calling this function in a if, data will be typed as Dog[]
  isArrayOfDogs(data: Cat[] | Dog[]): data is Dog[] {
    return dogs;
  }

  return (
    <ComponentNotModifiableByMe
      data={props.data}
      // If "Cat[] | Dog[]" is used above, TS says "Type 'Dog[]' is not assignable to type 'Cat[]'. ts(2322)"
      // If "any" is used above, this works okay, but defeats the purpose of TypeScript
      ...
    />
  );
}
like image 152
Guerric P Avatar answered Jun 12 '26 10:06

Guerric P



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!