TS2786: React TypeScript Component JSX Error
Problem Statement
When working with React and TypeScript, you might encounter the TS2786 error:
TS2786: 'ComponentName' cannot be used as a JSX component.
Its instance type 'ComponentName' is not a valid JSX element.
The types returned by 'render()' are incompatible with these types.
Type 'React.ReactNode' is not assignable to type 'import("/path/to/node_modules/@types/react/index").ReactNode'.This error typically occurs when there are multiple, incompatible versions of React type definitions (@types/react) in your project, causing TypeScript to become confused about which ReactNode type definition to use.
Root Cause
The main cause of this error is version mismatch in React type definitions. Various packages in your dependency tree may require different versions of @types/react, creating incompatible type definitions that conflict with each other.
Common scenarios include:
- Upgrading React (
@types/reactv18) while some dependencies still expect v17 - Multiple copies of
@types/reactin your node_modules - Third-party libraries with wildcard version requirements (
"@types/react": "*")
Solutions
1. Version Synchronization (Recommended)
Ensure all packages use compatible @types/react versions:
Using Yarn:
{
"resolutions": {
"@types/react": "18.2.0",
"@types/react-dom": "18.2.0"
}
}Using npm (v8+):
{
"overrides": {
"@types/react": "18.2.0",
"@types/react-dom": "18.2.0"
}
}After adding these, delete node_modules and your lock file (package-lock.json or yarn.lock), then reinstall dependencies.
2. TypeScript Configuration Fix
Add path aliasing to your tsconfig.json:
{
"compilerOptions": {
"paths": {
"react": ["./node_modules/@types/react"]
}
}
}3. Module Resolution Strategy
Configure TypeScript to use a compatible module resolution:
{
"compilerOptions": {
"moduleResolution": "bundler",
"skipLibCheck": true
}
}4. Dependency Analysis
Identify which packages are causing version conflicts:
# Yarn
yarn why @types/react
# npm
npm explain @types/reactCommon Scenarios and Fixes
Async Components
WARNING
Don't mark React components as async directly. Async functions return Promises, which are not valid JSX elements.
Incorrect:
export async const Component = () => {
// Async operations
return <div>Content</div>;
}Correct:
export const Component = () => {
const fetchData = async () => {
// Async operations
};
return <div>Content</div>;
}Router Redirects
When using redirects in conditional rendering, ensure you return valid JSX:
Problematic:
if (!isLoggedIn) return router.push("/login");Solution:
// Option 1: Return empty fragment
if (!isLoggedIn) {
router.push("/login");
return <></>;
}
// Option 2: Use framework-specific redirect component (Expo example)
import { Redirect } from "expo-router";
if (!isLoggedIn) return <Redirect href="/login" />;Children Rendering
When returning children directly, wrap them in a fragment:
// Problematic
return children;
// Fixed
return <>{children}</>;Framework-Specific Solutions
React Native
Ensure your tsconfig.json includes proper type definitions:
{
"compilerOptions": {
"types": ["react-native", "jest"]
}
}Styled Components v6+
If using styled-components v6+, uninstall @types/styled-components as the types are now bundled:
npm uninstall @types/styled-components
# or
yarn remove @types/styled-componentsVerification and Cleanup
After applying fixes:
- Delete
node_modulesand lock files - Clear package manager cache (
npm cache clean --forceoryarn cache clean) - Reinstall dependencies
- Verify only one version of
@types/reactis installed:
npm list @types/react
# or
yarn list --pattern "@types/react"Prevention
To avoid this issue in the future:
- Pin specific versions for critical type packages
- Regularly audit dependencies with
npm auditoryarn audit - Use consistent React versions across all dependencies
- Consider using
npm dedupeoryarn dedupeto eliminate duplicate packages
By understanding the root cause and applying the appropriate solution for your specific setup, you can resolve the TS2786 error and maintain a stable React TypeScript development environment.