287

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?

Ninjakannon
  • 3,283
  • 5
  • 42
  • 65
Asool
  • 7,423
  • 4
  • 25
  • 41
  • 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

15 Answers15

319

Just children: React.ReactNode

Ridd
  • 4,641
  • 3
  • 16
  • 19
  • 5
    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
  • 3
    @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
  • 2
    or `PropsWithChildren` – kimbaudi Feb 10 '21 at 19:19
69

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
  • 14,673
  • 5
  • 33
  • 40
  • 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
  • 1
    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
  • 2
    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
  • 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
57

This is what worked for me:

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

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

sunknudsen
  • 3,986
  • 1
  • 16
  • 34
  • 13
    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
  • 1
    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
  • or use `PropsWithChildren` as others have mentioned. I personally prefer it to `children: React.ReactNode` – kimbaudi Feb 10 '21 at 19:17
48

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
  • 6,287
  • 8
  • 45
  • 65
  • 2
    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
  • 1
    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
  • 1
    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
33

You can also use React.PropsWithChildren<P>.

type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;
Sibren
  • 491
  • 8
  • 9
15

you can declare your component like this:

const MyComponent: React.FunctionComponent = (props) => {
    return props.children;
}
jsina
  • 2,973
  • 24
  • 21
  • 1
    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
11

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
  • 30,106
  • 4
  • 111
  • 119
11

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
  • 779
  • 10
  • 8
9

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
  • 1,368
  • 11
  • 22
  • 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
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
  • 2,719
  • 1
  • 19
  • 12
6

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
  • 1,884
  • 1
  • 21
  • 25
5

This has always worked for me:

type Props = {
  children: JSX.Element;
};
Mr.Ghamkhar
  • 388
  • 6
  • 9
  • 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
3

I'm using the following

type Props = { children: React.ReactNode };

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

export default MyComponent;

Reinhard
  • 932
  • 1
  • 11
  • 22
  • 3
    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
  • propsWithChildren however also introduces some codesmells with {} being any – Mathijs Segers Apr 12 '21 at 11:23
2

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
  • 1,676
  • 15
  • 19
-3

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;
Dinesh Pandiyan
  • 4,702
  • 1
  • 23
  • 42