TypeScript requires explicit typing for the children prop in React components. Using React.PropsWithChildren ensures the children prop is correctly typed as ReactNode and helps prevent type errors when rendering components with child elements.
This TypeScript error occurs when you try to use the `children` prop in a React component without properly typing it in your props interface. Since React 18, the `children` prop is no longer implicitly included in React.FC, requiring developers to explicitly type it. The `React.PropsWithChildren` utility type is React's built-in solution for adding the children prop to your component's props. It's defined as `type PropsWithChildren<P> = P & { children?: ReactNode }`, which merges your custom props with an optional children property typed as ReactNode. Without proper typing, TypeScript cannot verify that your component is being used correctly, leading to potential runtime errors when components expect children but receive none, or when the wrong type of children is passed.
The most straightforward approach is to wrap your props interface with React.PropsWithChildren:
import React from 'react';
interface ButtonProps {
backgroundColor: string;
onClick: () => void;
}
// Wrap your props with PropsWithChildren
const Button = ({ backgroundColor, onClick, children }: React.PropsWithChildren<ButtonProps>) => {
return (
<button style={{ backgroundColor }} onClick={onClick}>
{children}
</button>
);
};This automatically adds children?: ReactNode to your props type.
For better reusability, have your interface extend React.PropsWithChildren:
import React from 'react';
interface CardProps extends React.PropsWithChildren {
title: string;
variant?: 'primary' | 'secondary';
}
const Card = ({ title, variant = 'primary', children }: CardProps) => {
return (
<div className={`card card-${variant}`}>
<h2>{title}</h2>
<div className="card-content">{children}</div>
</div>
);
};This approach is cleaner when you have multiple props and allows extending multiple interfaces.
If you need more control over whether children is required or optional, manually add it to your props:
import React, { ReactNode } from 'react';
// Optional children
interface ContainerProps {
className?: string;
children?: ReactNode;
}
// Required children
interface WrapperProps {
id: string;
children: ReactNode; // No question mark makes it required
}
const Container = ({ className, children }: ContainerProps) => {
return <div className={className}>{children}</div>;
};
const Wrapper = ({ id, children }: WrapperProps) => {
return <section id={id}>{children}</section>;
};Note that PropsWithChildren makes children optional by default. Use explicit typing if children should be required.
If you're using React.FC, you must now explicitly include children:
import React from 'react';
// Before React 18 (children was implicit)
// const Layout: React.FC<{ title: string }> = ({ title, children }) => { ... }
// After React 18 (children must be explicit)
interface LayoutProps {
title: string;
children?: React.ReactNode;
}
const Layout: React.FC<LayoutProps> = ({ title, children }) => {
return (
<div>
<h1>{title}</h1>
<main>{children}</main>
</div>
);
};
// Or use PropsWithChildren
const Layout: React.FC<React.PropsWithChildren<{ title: string }>> = ({ title, children }) => {
return (
<div>
<h1>{title}</h1>
<main>{children}</main>
</div>
);
};Many developers now prefer to avoid React.FC altogether and use regular function declarations.
PropsWithChildren vs Manual ReactNode
The PropsWithChildren utility type always makes children optional (children?: ReactNode). If your component requires children, you should manually type it as children: ReactNode (without the question mark).
Why React 18 Changed This
Prior to React 18, React.FC implicitly included children, which caused issues:
- Components that shouldn't accept children were typed as accepting them
- It violated the principle of explicit is better than implicit
- It made TypeScript types less accurate
Custom PropsWithChildren Variants
You can create your own utility types for more control:
// Required children
type PropsWithRequiredChildren<P = unknown> = P & { children: ReactNode };
// Specific children type
type PropsWithStringChildren<P = unknown> = P & { children: string };Type Safety Limitations
While TypeScript can enforce that children exists, it cannot deeply validate the structure of JSX children at compile time. You cannot make children "type safe" in the sense of enforcing specific component types or structures through TypeScript alone.
React.FC expects children prop to be defined
React.FC no longer includes implicit children prop
Warning: You provided a `selected` prop to a form field without an `onChange` handler
You provided a 'selected' prop without an onChange handler
Failed to load source map from suspense chunk
How to fix "Failed to load source map from suspense chunk" in React
Prop spreading could cause security issues
Prop spreading could cause security issues
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency