I'm making a component that has multiple sets of children.
The question React component with two sets of children suggests to index children
, as in props.children[0]
. This works great in JavaScript.
But in TypeScript, I'm getting a type error, even though the code works fine at runtime.
function MyComponent(props: { children: React.ReactNode }) {
return <>
...
{props.children[0]}
...
{props.children[1]}
...
</>;
}
TypeScript fails with the following error messages on props.children[0]
:
Object is possibly 'null' or 'undefined'.
ts(2533)
Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal'.
Property '0' does not exist on type 'string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal'.
ts(7053)
How do I make it typecheck?
CodePudding user response:
You need to tell Typescript that your component needs multiple children by putting the array brackets:
function MyComponent(props: { children: React.ReactNode[] }) {
// ...
}
If your component accepts exactly 2 children, a tuple type would be preferable so that Typescript will enforce having 2 children:
function MyComponent(props: { children: [React.ReactNode, React.ReactNode] }) {
// ...
}
If your component accepts 2 or more children, you can specify a tuple with a rest element:
function MyComponent(props: { children: [React.ReactNode, ...React.ReactNode[]] }) {
// ...
}
CodePudding user response:
You can use ReactNode[]
instead of ReactNode
function MyComponent(props: { children: React.ReactNode[] }) {
return <>
{props.children[0]}
{props.children[1]}
</>;
}
function TestComponent() {
return <MyComponent>
<span>Element 1</span>
<span>Element 2</span>
{'string test'}
{2}
{true}
</MyComponent>
}
CodePudding user response:
If your component always attempts to render at least 2 child nodes, then you should explicitly type the children
parameter that way:
import {type ReactElement, type ReactNode} from 'react';
function MyComponent(props: {
children: [ReactNode, ReactNode, ...readonly ReactNode[]];
}): ReactElement {
return <>
...
{props.children[0]}
...
{props.children[1]}
...
</>;
}
By doing so, TypeScript will emit a compiler error diagnostic if you don't provide at least two children:
function App (): ReactElement {
return (
<MyComponent>{/*
~~~~~~~~~~~
Type '{ children: []; }' is not assignable to type '{ children: [ReactNode, ReactNode, ...ReactNode[]]; }'.
Types of property 'children' are incompatible.
Type '[]' is not assignable to type '[ReactNode, ReactNode, ...ReactNode[]]'.
Source has 0 element(s) but target requires 2.(2322) */}
</MyComponent>
);
}
Similarly, when you only provide one child node:
function App (): ReactElement {
return (
<MyComponent>{/*
~~~~~~~~~~~
This JSX tag's 'children' prop expects type '[ReactNode, ReactNode, ...ReactNode[]]'
which requires multiple children, but only a single child was provided.(2745) */}
<div></div>
</MyComponent>
);
}
But as soon as you provide at least two, the diagnostic disappears:
function App (): ReactElement {
return (
<MyComponent>
<div></div>
<div></div>
</MyComponent>
);
}