What is the type of the 'children' prop?
Asked Answered
P

28

741

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?

Pow answered 9/12, 2018 at 2:38 Comment(2)
To avoid reinventing wheel, you can alternatively use React.FC to define your Functional Component. i e., const layout React.FC = (props) => {/*component body*/}Jeepers
you can use const XyzComponent = ({ title, children }: React.PropsWithChildren<XyzComponentPropsType> => {}`Erich
G
956

Just children: React.ReactNode.

Gertrudegertrudis answered 29/7, 2019 at 11:57 Comment(12)
This is the correct answer here ! JSX.Element is not good enough since a valid React children could be a string, a boolean, null... ReactChild is incomplete too for the same reasonsEquipoise
@PierreFerry The issue is, almost anything can be assigned to ReactNode. It doesn't help in terms of type safety, similar to typing children as any - see my answer for an explanation.Mirepoix
Thanks for your response @ford04. In my use case i want children to be loosely type. My component accept any kind of valid React children. So i believe this is still the answer i was looking for :)Equipoise
or PropsWithChildrenInvertebrate
Confused...isn't that what OP already has?Erysipeloid
@JanacMeena it's funny but people were finding this question when didn't know what type they should add to the children's element. It's simply just one of the first topics on Google. So if you don't know what TS type add to the element you probably will google something like "typescript react children", find this topic and the first answer, even if the question is quite about something different :)Gertrudegertrudis
With this answer, I get "object is possibly undefined" pointing at the this in this.props.childrenDidier
Adding that JSX.Element is also not good because you can't pass multiple elements to it (without using a fragment).Morello
React.ReactNode does not allow multiple elements as children though.Coccyx
I would add | React.ReactNode[] to also allow multiple childrenLeuco
The React.ReactNode type does allow multiple children. It is a union type which includes ReactFragment, another union type which includes Iterable<ReactNode> (in older versions of React it was Array<ReactNode>) Code here: github.com/facebook/react/blob/main/packages/shared/… Therefore, an array of ReactNodes is already a valid ReactNode. You shouldn't need to use | React.ReactNode[]Glutamine
this answer does not help with a proper explanation for @Ridd. "When you pass PropsWithChildren to your component prop FooProps, you get the children prop internally typed. In most cases, this is the recommended way to go about typing the children prop because it requires less boilerplate and the children prop is implicitly typed." - this article helped me understand the child prop type fully: blog.logrocket.com/using-react-children-prop-with-typescript/…Indolence
I
129

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}</>;
Invective answered 9/12, 2018 at 3:43 Comment(8)
I don't understand why it's needed to wrap children in a React Fragment. Care to explain? In React it's perfectly valid to just return children;.April
Not if children are an array. If that's the case you need to either wrap them in a single node or use React Fragments.Invective
Yeah, in my code I have: return React.Children.count(children) > 1 ? <>{children}</> : children, but typescript complains about that. I replaced it with just <>{children}</>.April
It complains because children is a list of elements that happens to contain only 1 item. I think it would work if you did return React.Children.count(children) > 1 ? <>{children}</> : children[0] @AprilAegrotat
This doesn't appear to be working in newer versions of React. I console logged and can confirm that I have a children prop, but even with <React.Fragment> surrounding {props.children} I am not returning anything.Franchot
How about when children is a function?Uredium
Wrappping into the Fragment <></> - here is the point! Thanks)Adios
With this, I got an error of '<component>' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of 'children' is 'ReactElement<any, string | JSXElementConstructor<any>> | null'.ts(2747)` when the children of the component was a string. How would I fix that?Rattlehead
P
101

You can also use React.PropsWithChildren<P>.

type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;
Plebe answered 23/6, 2020 at 11:35 Comment(4)
This is exactly what I've been doing and I think it's the cleaner way to use the right typing.Infra
I like this solution because it is extensible. type AuthProviderProps = React.PropsWithChildren<{}> allows me to encapsulate React types, and extend with my own when needed.Cofferdam
cleanest way, the one i was looking forTitulary
This feels the cleanest because it's using React's own published types so if the definition of what constitutes a react child changes in future versions of React, it is reasonable to assume that this type will also be updated. Solutions based on ReactChild | ReactChildren, would probably need to be updated in that case.Fabrication
R
91

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[];
}
Resee answered 3/6, 2020 at 10:26 Comment(7)
For anyone who ended up here, this is wrong. ReactChildren does not equal to ReactChild[] since it is type for utility function. reactjs.org/docs/react-api.html#reactchildren. if you use ReactChild | ReactChildren , you won't be able to pass children as an array.Flamsteed
@Flamsteed Thanks for that. I added the flat arrays definition to the answer. It should cover your case too. Let me know.Resee
thank you! However, I don't think ReactChildren is the right type here. I think children: ReactChild | ReactChild[] is enough or just ReactNodeFlamsteed
I disagree. Its better to create a type/interface as ReactNode compared to ReactChild and ReactChildren since it accepts more than just ReactChild/ReactChildren. Or even better, use PropsWithChildren as others have mentioned.Invertebrate
@deprecated — - This type is not relevant when using React. Inline the type instead to make the intent clear.Titulary
ReactChild was deprecated starting in React 18, but if you want to require the children to be passed, you can do: NonNullable<React.ReactNode>. (NonNullable is a built-in Typescript utility type)Ledezma
Deprecated solutionSpindell
V
84

This is what worked for me:

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

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

Voltaire answered 4/1, 2019 at 18:36 Comment(4)
That's not broad enough of a definition. The child could be a string.Kistner
At least this example worked for me since my component was supposed to expect 1 or more JSX.Elements. Thanks!Byline
This will not work with JavaScript expressions as the children <MyComponent>{ condition ? <span>test</span> : null}</MyComponent>. Using children: ReactNode will work.Contexture
or use PropsWithChildren as others have mentioned. I personally prefer it to children: React.ReactNodeInvertebrate
A
25

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
Armistead answered 3/9, 2020 at 6:16 Comment(0)
S
19
import { ReactNode, FC } from 'react'

type Props = { children: ReactNode }

const App: FC<Props> = ({children}) => (<div>{children}</div>)
Systemic answered 19/11, 2021 at 3:13 Comment(1)
FC already has children, so no need to redeclare itLaccolith
P
16

I'm using the following

type Props = { children: React.ReactNode };

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

export default MyComponent;
Philbert answered 25/12, 2020 at 16:37 Comment(3)
the general consensus today is that React.FunctionComponent (or the shorthand React.FC) is discouraged. In your case, I would remove React.FC usage and just do const MyComponent = ({children}: PropsWithChildren<{}>)Invertebrate
propsWithChildren<{}> however also introduces some codesmells with {} being anyDarciedarcy
If you are using React.FC, there is no need to include children type, as it is already defined on the base FC typings.Jeaniejeanine
H
15

you can declare your component like this:

const MyComponent: React.FunctionComponent = (props) => {
    return props.children;
}
Heifetz answered 13/8, 2019 at 7:2 Comment(1)
the general consensus today is that React.FunctionComponent (or the shorthand React.FC) is discouraged. In your case, I would remove React.FC usage and just do const MyComponent = ({children}: PropsWithChildren<{}>)Invertebrate
M
15

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.

Mirepoix answered 17/3, 2020 at 11:39 Comment(0)
C
11

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 :)

Contexture answered 5/10, 2019 at 17:55 Comment(1)
Control + click (on windows) takes you to said type-definition. May be common knowledge but I had to look up. Thanks for teaching us to fish instead of just giving fish btw.Accidence
U
10

You can also use JSX.ElementChildrenAttribute

export default function Layout({children}: JSX.ElementChildrenAttribute) {
    return <div>
        {children}
    </div>
}
Unsnarl answered 4/8, 2021 at 10:8 Comment(0)
K
9

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.

Kistner answered 25/4, 2019 at 23:11 Comment(0)
S
8

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 };

Spector answered 13/5, 2020 at 10:37 Comment(3)
What is P in the case of that type?Mendelssohn
P is the type of your component's propsSpector
Yes! this worked nicely. interface LayoutProps {} const Layout = ({children}: PropsWithChildren<LayoutProps>) => {...}Coterminous
P
7

For me "JSX.Element" works,

interface childrenProps {
    children: JSX.Element;
}

const index = ({ children }: childrenProps) => {
    return (
        <>
            <NavBar />
            {children}
        </>
    );
};

export default index;
Philosophism answered 24/7, 2022 at 10:30 Comment(1)
JSX.Element is one type that a child can be, but it could also be a String or a number, etc... ReactNode covers all cases, see https://mcmap.net/q/63324/-what-is-the-type-of-the-39-children-39-propAllele
I
6

This has always worked for me:

type Props = {
  children: JSX.Element;
};
Incardinate answered 17/8, 2020 at 21:35 Comment(2)
I would recommend just using React.PropsWithChildren<{}> or at least React.ReactNode instead of JSX.Element since it accpets more than just Element typeInvertebrate
This work for me too. I think typescript typings is becoming messy now.Selfhelp
S
4

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/>
)
Schlieren answered 4/2, 2020 at 11:46 Comment(0)
V
4

The easiest way to define children prop is to use ReactNode type.

It consists of:

type ReactNode = ReactElement | string | number | ReactFragment | ReactPortal | boolean | null | undefined;

But if you use FC or FunctionComponent and React < 18 like this:

import React, { FC } from 'react'

export const ParentComponent: FC = ({ children }) => (
  <ChildComponent>
    {children}
  </ChildComponent>
)

You don't have to set children prop. Because FC/FunctionComponent defined it for you with PropsWithChildren:

type PropsWithChildren<P> = P & { children?: ReactNode | undefined };
Veliavelick answered 21/2, 2023 at 9:4 Comment(1)
thanks, but I am using the FC type, and typescript isn't giving me the children props, I have to define it myself inside an interface when I provide it with parameter types as FC<MyPropsInterface>Intima
H
3

You can also extends React.PropsWithChildren to your interface which contains children property.

interface Props extends React.PropsWithChildren{
    listItems: Items[],
    clickItem?: () => void,
    
}

Or you can directly define the children

interface Props{
    listItems: Items[],
    clickItem?: () => void,
    children: React.ReactNode  
}

const List:FC<Props> = ({listItems,clickItem,children}) =>  {

  return (
    <>
    {children}
    </>
    
  )
}

Or you can do like this. This is a another way to defining prop type

const List = ({ children }: {children: React.ReactNode}) =>  {
Homochromatic answered 6/7, 2022 at 17:25 Comment(0)
G
2
  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>
)
Gordie answered 19/8, 2021 at 11:17 Comment(0)
M
2

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>;
}
Marden answered 27/1, 2022 at 7:46 Comment(0)
H
1

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}</>;
Hemorrhoid answered 21/4, 2022 at 17:9 Comment(0)
W
1

This is how I did this:

import React, { ReactNode } from "react";

type Props = {
  children: ReactNode;
};

export default function Outline({ children }: Props) {
  return (
    <div>
      <h3>Top</h3>
      {children}
      <h3>Botton</h3>
    </div>
  );
}
Windbag answered 22/6, 2023 at 11:47 Comment(0)
L
1

There is problem in return of Aux component because children can be string, null, array or element but layout component must need react element, so you have to cover up your props.children with div or React.Fragment. Then after every time layout component will get react element from aux component something like below.

import * as React from 'react';

export interface AuxProps  { 
    children: React.ReactNode
 }


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

export default aux;
Lancelle answered 12/2 at 8:8 Comment(0)
H
0

this solution works perfectly fine for me

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

update: a comprehensive example so that it is easier to understand.

interface ChildProps {}

class ChildComponent extends React.Component<ChildProps> {}

interface ParentProps {
    children: Array<ReactElement<ChildProps, JSXElementConstructor<ChildComponent>>>;
}

class ParentComponent extends React.Component<ParentProps> {}
Haiku answered 19/4, 2022 at 12:38 Comment(1)
If your "children" should be safely typed, within your parent component, this the one and only solution. Thank you very much, Sir!Prussian
P
0

You can use children: PropsWithChildren<{}>

Profant answered 9/6, 2023 at 11:4 Comment(0)
L
0

If you want to require that children are passed in to your component without allowing null/undefined children, you can use:

  children: NonNullable<React.ReactNode>

(NonNullable is a built-in TypeScript utility type that excludes null and undefined from any type.)

Note: there is one loophole here - it allows an empty array of ReactNode objects to be passed in. If you want to prevent that case then you'd need to create your own custom more explicit type.

Otherwise (if you want to allow children to be empty or you don't care), use React.PropsWithChildren or children: React.ReactNode as recommended in other answers here, and that will cover all possible types of children (or no children).

Ledezma answered 20/7, 2023 at 18:57 Comment(0)
C
-1
children: ReactElement

worked for me.

Complaisant answered 20/11, 2023 at 13:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.