TypeScript and React - children type?
ReactjsTypescriptJsxtypescript2.0Reactjs 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
orundefined
(which is ignored)Number
String
- A
React element
(result ofJSX
) - 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.
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[]
).
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
-
you should know that any react component should return
null
orReact.Element
, but the type ofprops.children
isReact.ReactNode
, so you need to use theprops.children
inside anElement
to make the babel configure the constructor of theElement
. -
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;