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:
instanceofN/A, this checks against classes, but I have types
typeofN/A, this checks against primitive types, but I have custom TypeScript types
inThis would probably work if I had
Cat | Dog. But I have arrays, and it's valid in my app fordatato be an empty array. So, I can't rely on checking the first element ofdata, because it might not exist.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()orisDog()function.discriminated union
N/A, there is no
kindproperty 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.
dataas an union type? Either define it asCat[] | Dog[]or(Cat | Dog)[].ComponentNotModifiableByMeonly seems to accept cats. Do you have a conditional in your real code where you use another component if you have a dog?ComponentNotModifiableByMeworks with bothCats andDogs. It's just a generic list display widget. I'm guessing the TS compiler always chooses to say "[the second of the union types] is not assignable to [the first of the union types]" in this situation where it can't determine the type for itself. If I reverse the order, the error is reversed as well.