690

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?

Flip
  • 6,233
  • 7
  • 46
  • 75
Asool
  • 13,031
  • 7
  • 35
  • 49
  • 3
    To avoid reinventing wheel, you can alternatively use React.FC to define your Functional Component. i e., `const layout React.FC = (props) => {/*component body*/}` – Kashif Nazar May 26 '21 at 22:21
  • 4
    you can use const XyzComponent = `({ title, children }: React.PropsWithChildren` => {}` – STEEL Jul 11 '22 at 08:39

26 Answers26

888

Just children: React.ReactNode.

Ridd
  • 10,701
  • 3
  • 19
  • 20
  • 27
    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 reasons – Pierre Ferry Jan 27 '20 at 15:56
  • 8
    @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](https://stackoverflow.com/a/60721650/5669456) for an explanation. – ford04 Mar 17 '20 at 13:29
  • 2
    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 :) – Pierre Ferry Mar 24 '20 at 14:19
  • 14
    or `PropsWithChildren` – kimbaudi Feb 10 '21 at 19:19
  • 33
    Confused...isn't that what OP already has? – Janac Meena Jun 26 '21 at 13:33
  • 14
    @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 :) – Ridd Apr 22 '22 at 07:41
  • With this answer, I get "object is possibly undefined" pointing at the `this` in `this.props.children` – Caleb Jay May 25 '22 at 07:40
  • Adding that `JSX.Element` is also not good because you can't pass multiple elements to it (without using a fragment). – User Dec 09 '22 at 17:29
  • 1
    React.ReactNode does not allow multiple elements as children though. – Ville Dec 14 '22 at 12:52
  • 1
    I would add `| React.ReactNode[]` to also allow multiple children – DarkTrick Jan 06 '23 at 16:14
  • The `React.ReactNode` type does allow multiple children. It is a union type which includes `ReactFragment`, another union type which includes `Iterable` (in older versions of React it was `Array`) Code here: https://github.com/facebook/react/blob/main/packages/shared/ReactTypes.js Therefore, an array of `ReactNode`s is already a valid `ReactNode`. You shouldn't need to use `| React.ReactNode[]` – Peter Cole Jan 25 '23 at 11:04
  • 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: https://blog.logrocket.com/using-react-children-prop-with-typescript/#using-functioncomponent-fc-type – ib95 Jun 27 '23 at 09:54
127

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}</>;
Karol Majewski
  • 23,596
  • 8
  • 44
  • 53
  • 1
    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;`. – sanfilippopablo Jul 25 '19 at 01:48
  • 3
    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. – Karol Majewski Jul 25 '19 at 09:48
  • 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}>`. – sanfilippopablo Jul 25 '19 at 14:38
  • 4
    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]` @sanfilippopablo – tamj0rd2 Aug 17 '19 at 19:27
  • 1
    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 `````` surrounding ```{props.children}``` I am not returning anything. – Mark Feb 29 '20 at 00:09
  • How about when `children` is a function? – t3__rry Jun 25 '20 at 09:16
  • Wrappping into the Fragment <>> - here is the point! Thanks) – Ihor Oct 27 '21 at 15:27
  • With this, I got an error of '' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of 'children' is 'ReactElement> | null'.ts(2747)` when the children of the component was a string. How would I fix that? – Manpreet Dec 16 '22 at 21:18
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[];
}
Wilk
  • 7,873
  • 9
  • 46
  • 70
  • 12
    For anyone who ended up here, this is wrong. `ReactChildren` does not equal to `ReactChild[]` since it is type for utility function. https://reactjs.org/docs/react-api.html#reactchildren. if you use `ReactChild | ReactChildren` , you won't be able to pass children as an array. – kay Jan 07 '21 at 07:24
  • @kay Thanks for that. I added the flat arrays definition to the answer. It should cover your case too. Let me know. – Wilk Jan 07 '21 at 15:26
  • 3
    thank you! However, I don't think `ReactChildren` is the right type here. I think `children: ReactChild | ReactChild[]` is enough or just `ReactNode` – kay Jan 08 '21 at 01:54
  • 4
    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. – kimbaudi Feb 10 '21 at 19:12
  • 1
    @deprecated — - This type is not relevant when using React. Inline the type instead to make the intent clear. – ThomasP1988 Sep 27 '22 at 20:45
  • `ReactChild` was deprecated starting in React 18, but if you want to require the children to be passed, you can do: `NonNullable`. (NonNullable is a built-in Typescript utility type) – Matt Browne Jul 20 '23 at 18:49
91

You can also use React.PropsWithChildren<P>.

type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;
Sibren
  • 1,068
  • 11
  • 11
  • 4
    This is exactly what I've been doing and I think it's the cleaner way to use the right typing. – Gustavo Straube Sep 03 '20 at 15:02
  • 4
    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. – Dragos May 25 '21 at 17:55
  • 2
    cleanest way, the one i was looking for – ThomasP1988 Feb 14 '22 at 16:06
  • 1
    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. – pgraham Mar 06 '22 at 17:01
81

This is what worked for me:

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

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

sunknudsen
  • 6,356
  • 3
  • 39
  • 76
  • 17
    That's not broad enough of a definition. The child could be a string. – Mike S Apr 25 '19 at 23:09
  • At least this example worked for me since my component was supposed to expect 1 or more JSX.Elements. Thanks! – Italo Borges May 28 '19 at 15:07
  • 2
    This will not work with JavaScript expressions as the children `{ condition ? test : null}`. Using `children: ReactNode` will work. – Nickofthyme Oct 05 '19 at 17:56
  • 2
    or use `PropsWithChildren` as others have mentioned. I personally prefer it to `children: React.ReactNode` – kimbaudi Feb 10 '21 at 19:17
23

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
Gapur Kassym
  • 1,131
  • 12
  • 10
19
import { ReactNode, FC } from 'react'

type Props = { children: ReactNode }

const App: FC<Props> = ({children}) => (<div>{children}</div>)
Ravi Makwana
  • 2,782
  • 1
  • 29
  • 41
16

I'm using the following

type Props = { children: React.ReactNode };

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

export default MyComponent;
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Reinhard
  • 1,516
  • 1
  • 18
  • 25
  • 7
    the general consensus today is that React.FunctionComponent (or the shorthand React.FC) is [discouraged](https://github.com/facebook/create-react-app/pull/8177). In your case, I would remove `React.FC` usage and just do `const MyComponent = ({children}: PropsWithChildren<{}>)` – kimbaudi Feb 10 '21 at 19:14
  • 1
    propsWithChildren<{}> however also introduces some codesmells with {} being any – Mathijs Segers Apr 12 '21 at 11:23
  • 2
    If you are using `React.FC`, there is no need to include `children` type, as it is already defined on the base FC typings. – wentjun Sep 09 '21 at 05:31
15

you can declare your component like this:

const MyComponent: React.FunctionComponent = (props) => {
    return props.children;
}
jsina
  • 4,433
  • 1
  • 30
  • 28
  • 7
    the general consensus today is that React.FunctionComponent (or the shorthand React.FC) is [discouraged](https://github.com/facebook/create-react-app/pull/8177). In your case, I would remove `React.FC` usage and just do `const MyComponent = ({children}: PropsWithChildren<{}>)` – kimbaudi Feb 10 '21 at 19:18
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.

Community
  • 1
  • 1
ford04
  • 66,267
  • 20
  • 199
  • 171
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 :)

Nickofthyme
  • 3,032
  • 23
  • 40
  • 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. – gcr Feb 16 '21 at 02:56
10

You can also use JSX.ElementChildrenAttribute

export default function Layout({children}: JSX.ElementChildrenAttribute) {
    return <div>
        {children}
    </div>
}
francis
  • 3,852
  • 1
  • 28
  • 30
8

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.

Mike S
  • 3,058
  • 1
  • 22
  • 12
8

For me "JSX.Element" works,

interface childrenProps {
    children: JSX.Element;
}

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

export default index;
Samiullah
  • 89
  • 1
  • 4
7

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

Tim Iles
  • 2,232
  • 2
  • 24
  • 26
6

This has always worked for me:

type Props = {
  children: JSX.Element;
};
Mr.Ghamkhar
  • 557
  • 8
  • 12
  • 1
    I would recommend just using `React.PropsWithChildren<{}>` or at least `React.ReactNode` instead of `JSX.Element` since it accpets more than just `Element` type – kimbaudi Feb 10 '21 at 19:15
  • This work for me too. I think typescript typings is becoming messy now. – govo Apr 16 '21 at 06:57
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/>
)
Denis
  • 3,167
  • 1
  • 22
  • 23
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>
)
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>;
}
CodingYourLife
  • 7,172
  • 5
  • 55
  • 69
2

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}) =>  {
Ishan Fernando
  • 2,758
  • 1
  • 31
  • 38
2

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 };
Pavel Sturov
  • 315
  • 7
  • 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` – Normal Mar 04 '23 at 06:58
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}</>;
Kivylius
  • 6,357
  • 11
  • 44
  • 71
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> {}
Champignon
  • 37
  • 4
  • If your "children" should be safely typed, within your parent component, this the one and only solution. Thank you very much, Sir! – BenjaminR Jun 24 '22 at 07:37
0

You can use children: PropsWithChildren<{}>

Mnsf
  • 1
0

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>
  );
}
Flavio Oliveira
  • 381
  • 4
  • 12
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).

Matt Browne
  • 12,169
  • 4
  • 59
  • 75