I have 3 different types of items, which i have interfaces of
interface TypeA{
name: string;
}
interface TypeB{
count: number;
}
interface TypeC{
date: Date;
}
This items should be rendered in a list of items (in a list all items are from the same type). Depending on the type of the item, a different method is called, which will render different layouts.
export const ListItem: React.FC<ListItemProps> = (props) => {
let item = null;
switch (props.type) {
case "A":
item = renderTypeA(props);
break;
case "B":
item = renderTypeB(props);
break;
case "C":
item = renderTypeC(props);
break;
}
return item;
};
The method should accept just items from the desired type.
const renderTypeA = (props: TypeAProps) => {
{...}
};
The problem is that I can't get Typescript to recognize all properties of the types and also only auto-complete the respective types.
I have also tried it with a union type "ListItemTypes",
type ListItemTypes = TypeA | TypeB | TypeC
export const ListItem: React.FC<ListItemTypes> = (props) => {
...
};
but when I then try to include the ListItem, I always get an error that properties are missing.
<ListItem {...item /> <--- is telling me that properties are missing
Does anyone know how I can fix this problem?
I checked your code, it's throwing errors because you're destructuring an array into your component. In your code
const renderItem = () => {
const sampleData = [
{
type: "A",
count: 12,
},
];
// incorrectly destructuring sampleData here
return <ListItem {...sampleData} />;
};
You should be able to achieve the expected result with this instead:
const renderItemA = () => {
const sampleData = {
type: "A" as const, // notice const assertion here
name: "name"
};
return <ListItem {...sampleData} />;
};
Because you defined type
as literal type, you need const assertion so that
no literal types in that expression should be widened (e.g. no going from "hello" to string)