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?
const layout React.FC = (props) => {/*component body*/}
({ title, children }: React.PropsWithChildren<XyzComponentPropsType>
=> {}`
Just children: React.ReactNode
.
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}</>;
children
in a React Fragment. Care to explain? In React it's perfectly valid to just return children;
.
children
are an array. If that's the case you need to either wrap them in a single node or use React Fragments.
return React.Children.count(children) > 1 ? <>{children}</> : children
, but typescript complains about that. I replaced it with just <>{children}</>
.
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
<React.Fragment>
surrounding {props.children}
I am not returning anything.
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[];
}
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.
ReactChildren
is the right type here. I think children: ReactChild | ReactChild[]
is enough or just ReactNode
ReactNode
compared to ReactChild
and ReactChildren
since it accepts more than just ReactChild/ReactChildren. Or even better, use PropsWithChildren
as others have mentioned.
This is what worked for me:
interface Props {
children: JSX.Element[] | JSX.Element
}
Edit I would recommend using children: React.ReactNode
instead now.
<MyComponent>{ condition ? <span>test</span> : null}</MyComponent>
. Using children: ReactNode
will work.
PropsWithChildren
as others have mentioned. I personally prefer it to children: React.ReactNode
You can also use React.PropsWithChildren<P>
.
type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;
type AuthProviderProps = React.PropsWithChildren<{}>
allows me to encapsulate React types, and extend with my own when needed.
ReactChild | ReactChildren
, would probably need to be updated in that case.
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
you can declare your component like this:
const MyComponent: React.FunctionComponent = (props) => {
return props.children;
}
React.FC
usage and just do const MyComponent = ({children}: PropsWithChildren<{}>)
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.
I'm using the following
type Props = { children: React.ReactNode };
const MyComponent: React.FC<Props> = ({children}) => {
return (
<div>
{ children }
</div>
);
export default MyComponent;
React.FC
usage and just do const MyComponent = ({children}: PropsWithChildren<{}>)
React.FC
, there is no need to include children
type, as it is already defined on the base FC typings.
import { ReactNode, FC } from 'react'
type Props = { children: ReactNode }
const App: FC<Props> = ({children}) => (<div>{children}</div>)
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[]
).
https://i.stack.imgur.com/ffpa8.png
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 :)
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.
You can also use JSX.ElementChildrenAttribute
export default function Layout({children}: JSX.ElementChildrenAttribute) {
return <div>
{children}
</div>
}
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 };
P
in the case of that type?
P
is the type of your component's props
interface LayoutProps {} const Layout = ({children}: PropsWithChildren<LayoutProps>) => {...}
This has always worked for me:
type Props = {
children: JSX.Element;
};
React.PropsWithChildren<{}>
or at least React.ReactNode
instead of JSX.Element
since it accpets more than just Element
type
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/>
)
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>;
}
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. 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>
)
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> {}
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}</>;
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}) => {
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;
Success story sharing
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 reasonsReactNode
. It doesn't help in terms of type safety, similar to typingchildren
asany
- see my answer for an explanation.PropsWithChildren