I would like to only allow specific components as children. For example, let's say I have a Menu component, that should only contain MenuItem
as children, like this:
<Menu>
<MenuItem />
<MenuItem />
</Menu>
So I would like Typescript to throw me an error in the IDE when I try to put another component as child. Something warning me that I should only use MenuItem
as children. For example in this situation:
<Menu>
<div>My item</div>
<div>My item</div>
</Menu>
This thread is almost similar but does not include a TypeScript solution. I was wondering if the problem can be solved using TypeScript types and interfaces. In my imaginary world it would look like this, but of course the type checking is not working because the child component has an Element
type:
type MenuItemType = typeof MenuItem;
interface IMenu {
children: MenuItemType[];
}
const MenuItem: React.FunctionComponent<IMenuItem> = ({ props }) => {
return (...)
}
const Menu: React.FunctionComponent<IMenu> = ({ props }) => {
return (
<nav>
{props.children}
</nav>
)
}
const App: React.FunctionComponent<IApp> = ({ props }) => {
return (
<Menu>
<MenuItem />
<MenuItem />
</Menu>
)
}
Is there a way to achieve this with Typescript? Like to extend the Element type with something related only to a specific component?
Or what would be a good approach for being sure that a child is an instance of a specific component? Without having to add condition that looks at the child component displayName.
To do that you need to extract props interface from children component (and preferably also parent) and use it this way:
interface ParentProps {
children: ReactElement<ChildrenProps> | Array<ReactElement<ChildrenProps>>;
}
so in your case it would look like this:
interface IMenu {
children: ReactElement<IMenuItem> | Array<ReactElement<IMenuItem>>;
}
const MenuItem: React.FunctionComponent<IMenuItem> = ({ props }) => {
return (...)
}
const Menu: React.FunctionComponent<IMenu> = ({ props }) => {
return (
<nav>
{props.children}
</nav>
)
}