This TypeScript error occurs when returning the children prop directly from a React component. React expects a valid JSX element return type, but ReactNode (which includes undefined) cannot be returned directly without wrapping.
This error appears when using TypeScript with React and attempting to return the children prop directly from a component. The issue stems from a type mismatch between what TypeScript expects as a valid JSX return type and what the children prop is typed as. In React with TypeScript, the children prop is typed as ReactNode, which includes ReactElement, strings, numbers, fragments, portals, booleans, null, and undefined. However, React components cannot return undefined as a valid render output—they must return null instead. When you try to return children directly (like "return children;"), TypeScript cannot guarantee the return type is valid JSX because children might be undefined. JSX.Element is a narrower type that TypeScript uses to validate what can be rendered as JSX. Since ReactNode is broader and includes non-renderable values like undefined, TypeScript throws an error when you attempt to return children without wrapping it in valid JSX syntax like a fragment.
The simplest solution is to wrap the children prop in a fragment when returning it directly:
import { PropsWithChildren } from 'react';
function Wrapper({ children }: PropsWithChildren) {
return <>{children}</>;
}This ensures the return type is always valid JSX, even if children is undefined. Fragments have no practical DOM overhead and will compile away in production.
If you need to conditionally render children, explicitly handle the undefined case:
import { PropsWithChildren } from 'react';
function ConditionalWrapper({ isVisible, children }: PropsWithChildren<{ isVisible: boolean }>) {
if (!isVisible) return null;
return <>{children}</>;
}Always return null (not undefined) for empty renders to satisfy TypeScript's JSX requirements.
When manually typing props, always use ReactNode for children, not JSX.Element:
import { ReactNode } from 'react';
interface WrapperProps {
children: ReactNode; // Correct: accepts strings, numbers, elements, etc.
className?: string;
}
function Wrapper({ children, className }: WrapperProps) {
return <div className={className}>{children}</div>;
}ReactNode is the correct type for children as it represents all valid React child types including strings, numbers, and arrays.
JSX.Element is too restrictive for children and causes type errors:
// ❌ Wrong: JSX.Element doesn't accept strings or numbers
interface BadProps {
children: JSX.Element;
}
// ✅ Correct: ReactNode accepts all valid children
interface GoodProps {
children: ReactNode;
}If you use JSX.Element, you'll get errors like "Text in JSX has the type 'string', but the expected type of 'children' is 'Element'."
React provides a utility type that automatically adds children with the correct type:
import { PropsWithChildren } from 'react';
interface MyProps {
title: string;
}
function Component({ title, children }: PropsWithChildren<MyProps>) {
return (
<div>
<h1>{title}</h1>
{children}
</div>
);
}PropsWithChildren<T> returns T & { children?: ReactNode }, saving you from manually typing children.
Ensure you're using compatible versions to avoid type conflicts:
npm install --save-dev typescript@latest @types/react@latest @types/react-dom@latestTypeScript 5.1+ has improvements in how it infers types from React components. If using older versions, consider upgrading to get better type checking and fewer false positives.
For complex conditional rendering, explicitly specify the return type:
import { ReactElement, PropsWithChildren } from 'react';
function ComplexWrapper({ condition, children }: PropsWithChildren<{ condition: boolean }>): ReactElement | null {
if (condition) {
return <div>{children}</div>;
}
return null;
}This helps TypeScript understand your intent and provides better error messages if something goes wrong.
React.FC Considerations: Prior to React 18, React.FC automatically included children in the props type. This was removed in React 18 to make components more explicit about whether they accept children. If migrating from older code, you may need to add PropsWithChildren explicitly.
Fragment Performance: While <>{children}</> creates a fragment element, React's reconciliation algorithm optimizes this away in most cases, resulting in negligible performance impact. Fragments are a zero-cost abstraction in production builds.
Type Narrowing: If you need to validate that children is a specific type (e.g., only a single element), use React.Children utilities or custom type guards:
import { Children, isValidElement } from 'react';
function SingleChildWrapper({ children }: PropsWithChildren) {
const child = Children.only(children);
if (!isValidElement(child)) {
throw new Error('Child must be a valid React element');
}
return <div>{child}</div>;
}Server Components: In React Server Components, the children prop works identically but be aware that client-only components may have different serialization constraints when passed as children to server components.
React 19 Changes: React 19 introduced stricter typing around props.children, especially when dealing with objects. If upgrading, ensure your components explicitly handle children prop typing and avoid returning bare children without JSX wrapping.
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
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite