How to define the React children type in Typescript?

About

This article will show you how to override/define the type of children of your react component to a specific type in your props.

Step by Step Example

The component to refactor

In this example, we have a layout component that expects only buttons as children to create a button bar.

The base component is as follows where the props accepted are for div element (ie React.HTMLAttributes<HTMLDivElement>)

export function ButtonGroup(props: React.HTMLAttributes<HTMLDivElement>) {

    return (
        <div className={'btn-group flex-wrap'} {...props}/>
    )
}

Step 1: Changing the default children type

The props.children attributes by default have the type React.ReactNode or undefined

To override it to only buttons, you would:

  • use the Omit function to exclude the children attribute
  • add your children's type definition

Example:

export function ButtonGroup(
   props: Omit<React.HTMLAttributes<HTMLDivElement>,"children"> 
      & { 
          children: HTMLButtonElement[] 
          // with your button component
          // children: (ReactElement<typeof YourButtonComponent>|HTMLButtonElement)[]
      }) {
  ...
} 

Step2: Fixing the typescript error

Once you have changed your signature with your type definition, you will get the following typescript error:

TS2322: Type HTMLButtonElement is not assignable to type ReactNode
Type HTMLButtonElement is missing the following properties from type ReactPortal: props, key
index.d.ts(2318, 9): The expected type comes from property children which is declared here on type
DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>

React Typescript Children Override Error

Why? Because the div element in React is a React Node and excepts as children a ReactNode or undefined

It does not like your new definition.

To resolve this problem, you need to override the type by defining it back to a ReactNode (ie children as unknown as React.ReactNode)

Example:

export function ButtonGroup({children, ...props}: 
    Omit<React.HTMLAttributes<HTMLDivElement>, "children"> &
    {
        children: HTMLButtonElement[]
    }
) {

    return (
        <div className={'btn-group flex-wrap'} {...props}>
            {children as unknown as React.ReactNode}
        </div>
    )
}

Conclusion

And here you are, you got your typescript component that accepts your type in our case: only buttons.

Note that it adds some complexity and even if you have created a type children component, you may not want to deal with further typescript problem such as

  • type. An anchor may also be styled as a button
  • performance. Typescript needs to parse and apply narrower restrictions.

And leave the restriction to the developer.





Discover More
React Props Chrome Plugin
React - Props

props is the only object argument passed from a component to another component. Props are similar to State, but is public and not fully controlled by the component. You can also pass arguments to...



Share this page:
Follow us:
Task Runner