I'm trying to type a property of a React component using generics. The problem is when I try to render the component as a render prop through another component, it seems to no longer be able to "infer" the correct type - instead it defaults to unknown and I have to use "as any" to make things work.
I've put together a working example here. Note the comments and "as any"'s: https://stackblitz.com/edit/react-ts-4oyi3d?file=index.tsx
Here's the code:
type TabProps<T> = {
data?: T;
};
type TabsProps<T> = {
children: ({
childrenArr
}: {
childrenArr: React.ReactElement<TabProps<T>>[];
}) => React.ReactElement<TabProps<T>>[];
items: React.ReactElement<TabProps<T>>[];
};
type Data = { hello: string };
const Tab = <T extends unknown>({ data }: TabProps<T>) => <div>...</div>;
const Tabs = <T extends unknown>({ children, items }: TabsProps<T>) => {
const childrenArr = useMemo(() => (Array.isArray(items) ? items : [items]), [
items
]);
// ...
// In real application this is where manipulation of the elements in the childrenArr would take place
// Since this is just an example I'll just do this
const manipulatedchildrenArr = childrenArr.map(child => {
return {
...(child as any),
props: { data: { hello: "world is manipulated" } }
};
});
return (
<div>
<div>Hello</div>
<div>
{typeof children === "function"
? children({ childrenArr: manipulatedchildrenArr })
: children}
</div>
</div>
);
};
const App = () => {
const data: Data = { hello: "World" };
return (
<div className="App">
<Tabs items={[<Tab data={data} />]}>
{({ childrenArr }) =>
childrenArr.map(child => (
// Remove "as any" and it will be type unknown and result in an error
<div>{(child.props as any).data.hello}</div>
))
}
</Tabs>
</div>
);
};
As you can see the type of the data prop is lost.