TypeScript and React - children type?

ReactjsTypescriptJsxtypescript2.0

Reactjs Problem Overview


I have a very simple functional component as follows:

import * as React from 'react';

export interface AuxProps  { 
    children: React.ReactNode
 }

 
const aux = (props: AuxProps) => props.children;

export default aux;

And another component:

import * as React from "react";

export interface LayoutProps  { 
   children: React.ReactNode
}

const layout = (props: LayoutProps) => (
    <Aux>
        <div>Toolbar, SideDrawer, Backdrop</div>
        <main>
            {props.children}
        </main>
    <Aux/>
);

export default layout;

I keep on getting the following error:

> [ts] JSX element type 'ReactNode' is not a constructor function for JSX elements. Type 'undefined' is not assignable to type 'ElementClass'. [2605]

How do I type this correctly?

Reactjs Solutions


Solution 1 - Reactjs

Just children: React.ReactNode.

Solution 2 - Reactjs

In order to use <Aux> in your JSX, it needs to be a function that returns ReactElement<any> | null. That's the definition of a function component.

However, it's currently defined as a function that returns React.ReactNode, which is a much wider type. As React typings say:

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

Make sure the unwanted types are neutralized by wrapping the returned value into React Fragment (<></>):

const aux: React.FC<AuxProps> = props =>
  <>{props.children}</>;

Solution 3 - Reactjs

You can use ReactChildren and ReactChild:

import React, { ReactChildren, ReactChild } from 'react';
 
interface AuxProps {
  children: ReactChild | ReactChildren;
}

const Aux = ({ children }: AuxProps) => (<div>{children}</div>);

export default Aux;

If you need to pass flat arrays of elements:

interface AuxProps {
  children: ReactChild | ReactChild[] | ReactChildren | ReactChildren[];
}

Solution 4 - Reactjs

This is what worked for me:

interface Props {
  children: JSX.Element[] | JSX.Element
}

Edit I would recommend using children: React.ReactNode instead now.

Solution 5 - Reactjs

You can also use React.PropsWithChildren<P>.

type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;

Solution 6 - Reactjs

A React Node is one of the following types:

  • Boolean (which is ignored)
  • null or undefined (which is ignored)
  • Number
  • String
  • A React element (result of JSX)
  • An array of any of the above, possibly a nested one

Solution 7 - Reactjs

you can declare your component like this:

const MyComponent: React.FunctionComponent = (props) => {
    return props.children;
}

Solution 8 - Reactjs

The function component return type is limited to JSXElement | null in TypeScript. This is a current type limitation, pure React allows more return types.

Minimal demonstration snippet

You can either use a type assertion or Fragments as workaround:

const Aux = (props: AuxProps) => <>props.children</>; 
const Aux2 = (props: AuxProps) => props.children as ReactElement; 

ReactNode

children: React.ReactNode might be suboptimal, if the goal is to have strong types for Aux.

Almost anything can be assigned to current ReactNode type, which is equivalent to {} | undefined | null. A safer type for your case could be:

interface AuxProps {
  children: ReactElement | ReactElement[]
}

Example:

Given Aux needs React elements as children, we accidently added a string to it. Then above solution would error in contrast to ReactNode - take a look at the linked playgrounds.

Typed children are also useful for non-JSX props, like a Render Prop callback.

Solution 9 - Reactjs

I'm using the following

type Props = { children: React.ReactNode };

const MyComponent: React.FC<Props> = ({children}) => {
  return (
    <div>
      { children }
    </div>
  );

export default MyComponent;

Solution 10 - Reactjs

import { ReactNode, FC } from 'react'

type Props = { children: ReactNode }

const App: FC<Props> = ({children}) => (<div>{children}</div>)

Solution 11 - Reactjs

The general way to find any type is by example. The beauty of typescript is that you have access to all types, so long as you have the correct @types/ files.

To answer this myself I just thought of a component react uses that has the children prop. The first thing that came to mind? How about a <div />?

All you need to do is open vscode and create a new .tsx file in a react project with @types/react.

import React from 'react';

export default () => (
  <div children={'test'} />
);

Hovering over the children prop shows you the type. And what do you know -- Its type is ReactNode (no need for ReactNode[]).

enter image description here

Then if you click into the type definition it brings you straight to the definition of children coming from DOMAttributes interface.

// node_modules/@types/react/index.d.ts
interface DOMAttributes<T> {
  children?: ReactNode;
  ...
}

> Note: This process should be used to find any unknown type! All of them are there just waiting for you to find them :)

Solution 12 - Reactjs

From the TypeScript site: https://github.com/Microsoft/TypeScript/issues/6471

> The recommended practice is to write the props type as {children?: > any}

That worked for me. The child node can be many different things, so explicit typing can miss cases.

There's a longer discussion on the followup issue here: https://github.com/Microsoft/TypeScript/issues/13618, but the any approach still works.

Solution 13 - Reactjs

You can also use JSX.ElementChildrenAttribute

export default function Layout({children}: JSX.ElementChildrenAttribute) {
    return <div>
        {children}
    </div>
}

Solution 14 - Reactjs

These answers appear to be outdated - React now has a built in type PropsWithChildren<{}>. It is defined similarly to some of the correct answers on this page:

type PropsWithChildren<P> = P & { children?: ReactNode };

Solution 15 - Reactjs

This has always worked for me:

type Props = {
  children: JSX.Element;
};

Solution 16 - Reactjs

As a type that contains children, I'm using:

type ChildrenContainer = Pick<JSX.IntrinsicElements["div"], "children">

This children container type is generic enough to support all the different cases and also aligned with the ReactJS API.

So, for your example it would be something like:

const layout = ({ children }: ChildrenContainer) => (
    <Aux>
        <div>Toolbar, SideDrawer, Backdrop</div>
        <main>
            {children}
        </main>
    <Aux/>
)

Solution 17 - Reactjs

  1. you should know that any react component should return null or React.Element, but the type of props.children is React.ReactNode, so you need to use the props.children inside an Element to make the babel configure the constructor of the Element.

  2. the second rule of any react component is that the first letter of the naming should be a capital letter to let the react recognize that the component isn't a html tag.

so the code should be like this.

const Aux = (props: AuxProps) => <>props.children</>;

another hint if you still using typescript, the functional component should be type of React.FC like this

type Props = {
   title: string;
}

const Aux:React.FC<Props> = (props) =>
(
    <div>
        <h3>{props.title}</h3>
        { props.children }
        {/* children is exist by default in type React.FC */}
    </div>
)

Solution 18 - Reactjs

For me @Sibren's answer was not clear enough but I found this SO anwer and made it all inline (that's maybe not the shortest way but the one I find the easiest to grasp).

function MyComponentWithChildren({
	customProp,
	children, /*notice the children are implicit*/
}: React.PropsWithChildren<{ customProp: any }>) {
	return <div>{children}</div>;
}

Solution 19 - Reactjs

this solution works perfectly fine for me

interface Props {
    children: Array<ReactElement<ChildProps, JSXElementConstructor<ChildType>>>;
}

Solution 20 - Reactjs

You can create a simple component that outputs just children prop without type or interface with FC (functional component). You have to wrap with empty jsx tags <>, as children can be undefined or null:

import { FC } from "react";

export const Layout: FC = (props) => {
  return <>{props.children}</>;
};

-- or --

import { FC } from "react";

export const Layout: FC = ({ children }) => <>{children}</>;

Solution 21 - Reactjs

React components should have a single wrapper node or return an array of nodes.

Your <Aux>...</Aux> component has two nodes div and main.

Try to wrap your children in a div in Aux component.

import * as React from 'react';

export interface AuxProps  { 
  children: React.ReactNode
}

const aux = (props: AuxProps) => (<div>{props.children}</div>);

export default aux;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAsoolView Question on Stackoverflow
Solution 1 - ReactjsRiddView Answer on Stackoverflow
Solution 2 - ReactjsKarol MajewskiView Answer on Stackoverflow
Solution 3 - ReactjsWilkView Answer on Stackoverflow
Solution 4 - ReactjssunknudsenView Answer on Stackoverflow
Solution 5 - ReactjsSibrenView Answer on Stackoverflow
Solution 6 - ReactjsGapur KassymView Answer on Stackoverflow
Solution 7 - ReactjsjsinaView Answer on Stackoverflow
Solution 8 - Reactjsford04View Answer on Stackoverflow
Solution 9 - ReactjsReinhardView Answer on Stackoverflow
Solution 10 - ReactjsSirawich voungchuyView Answer on Stackoverflow
Solution 11 - ReactjsNickofthymeView Answer on Stackoverflow
Solution 12 - ReactjsMike SView Answer on Stackoverflow
Solution 13 - ReactjsfrancisView Answer on Stackoverflow
Solution 14 - ReactjsTim IlesView Answer on Stackoverflow
Solution 15 - ReactjsMr.GhamkharView Answer on Stackoverflow
Solution 16 - ReactjsDenisView Answer on Stackoverflow
Solution 17 - Reactjsعبد الحميد مرعيView Answer on Stackoverflow
Solution 18 - ReactjsCodingYourLifeView Answer on Stackoverflow
Solution 19 - ReactjsChampignonView Answer on Stackoverflow
Solution 20 - ReactjsKivyliusView Answer on Stackoverflow
Solution 21 - ReactjsDinesh PandiyanView Answer on Stackoverflow