Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Only allow specific components as children in React and Typescript

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.

like image 762
neiya Avatar asked Aug 23 '19 14:08

neiya


People also ask

How do you pass children in React TypeScript?

By invoking them between the opening and closing tags of a JSX element, you can use React children for entering data into a component. The React children prop is an important concept for creating reusable components because it allows components to be constructed together.

How do you pass a component as a child in React?

You can pass a component as props in React by using the built-in children prop. All elements you pass between the opening and closing tags of a component get assigned to the children prop.

Can React components have children?

React Components and Children In React, a component can have one, many, or no children.

What is this props children and when you should use it?

props. children }. The important thing to note here is that children are a special prop that is used to pass the data from the parent component to the children component but this data must be enclosed within the parent's opening and closing tag.


1 Answers

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>
  )
}
like image 125
Minwork Avatar answered Oct 12 '22 08:10

Minwork