This TypeScript error occurs when passing a component to a prop or utility that expects React.ComponentType, but the function signature returns JSX.Element instead of the broader ReactNode type.
This error appears when TypeScript detects a mismatch between what your component returns and what React.ComponentType expects. React.ComponentType is a union type that can represent both class and function components, and it expects function components to return ReactNode (which includes JSX.Element, strings, numbers, null, undefined, and more). When you explicitly type a function component as returning JSX.Element, TypeScript sees this as too narrow for React.ComponentType, which expects the more flexible ReactNode return type. This commonly happens when using higher-order components, render props, or passing components to libraries that expect React.ComponentType. The error indicates a type compatibility issue, not a runtime error - your component will work fine, but TypeScript's type system is preventing potentially unsafe type assignments.
The most straightforward fix is to update your component's return type to ReactNode, which is what React.ComponentType expects:
// Before - too narrow
const MyComponent = (props: Props): JSX.Element => {
return <div>{props.children}</div>;
};
// After - compatible with ComponentType
const MyComponent = (props: Props): React.ReactNode => {
return <div>{props.children}</div>;
};ReactNode is the appropriate return type for modern React components as it allows all valid return values (elements, strings, numbers, null, etc.).
Let TypeScript infer the return type automatically, which will typically infer the correct ReactNode type:
// Before - explicit but incompatible
const MyComponent = (props: Props): JSX.Element => {
return <div>{props.children}</div>;
};
// After - TypeScript infers the correct type
const MyComponent = (props: Props) => {
return <div>{props.children}</div>;
};TypeScript's inference is usually smart enough to determine the correct return type based on what you actually return.
If you're on TypeScript 5.1 or later with React 18+, React.FC is now a viable option:
// Modern React.FC usage
const MyComponent: React.FC<Props> = (props) => {
return <div>{props.children}</div>;
};
// Or with explicit children
type PropsWithChildren = Props & { children?: React.ReactNode };
const MyComponent: React.FC<PropsWithChildren> = (props) => {
return <div>{props.children}</div>;
};Note: React.FC was problematic in older versions, but TypeScript 5.1+ fixed the issues with implicit children and return types.
If your component returns an array of elements, wrap them in a Fragment:
// Before - returns JSX.Element[]
const MyComponent = (props: Props) => {
return [
<div key="1">First</div>,
<div key="2">Second</div>
];
};
// After - returns single ReactNode
const MyComponent = (props: Props) => {
return (
<>
<div>First</div>
<div>Second</div>
</>
);
};React.ComponentType expects a single ReactNode, not an array.
Ensure you're using compatible versions of TypeScript and @types/react:
# Check current versions
npm list typescript @types/react
# Update to latest versions
npm install --save-dev typescript@latest @types/react@latest @types/react-dom@latest
# Or with Yarn
yarn upgrade typescript @types/react @types/react-dom --latestMany type compatibility issues were resolved in TypeScript 5.1+ and React 18+ type definitions.
Understanding React Type Hierarchy:
The React type system has several related but distinct types:
- JSX.Element: The most specific - represents the result of a JSX expression
- React.ReactElement: Functionally the same as JSX.Element
- React.ReactNode: The broadest - includes elements, strings, numbers, null, undefined, booleans, and arrays
- React.ComponentType<P>: Union of React.FC<P> | React.ComponentClass<P> - represents any valid component type
When to Use Which Type:
- For component return types: Use React.ReactNode or let TypeScript infer
- For props that accept renderable content: Use React.ReactNode
- For props that accept components: Use React.ComponentType<Props>
- For HOC return types: Use React.ComponentType<Props>
React.FC Evolution:
React.FC was controversial in the TypeScript community because:
- Pre-TypeScript 5.1: It implicitly added children to props (unwanted in many cases)
- It didn't allow returning strings or numbers directly
- It made generic components awkward to type
As of TypeScript 5.1 and React 18, these issues are resolved, making React.FC acceptable again. However, many teams prefer explicit prop typing without React.FC for clarity.
Generic Components:
If you're building generic components, avoid React.FC as it doesn't support generics well:
// Doesn't work well with React.FC
function GenericComponent<T>(props: { items: T[] }) {
return <div>{props.items.length}</div>;
}Library Integration:
Some popular libraries (React Router, React Redux, testing libraries) expect React.ComponentType for component props. Always ensure your component signatures match the expected type, typically by using ReactNode return types or letting TypeScript infer.
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