This TypeScript error occurs when React components have missing or incorrect type definitions, causing TypeScript to infer an "unknown" type instead of the expected Function Component type. It typically happens with async components, missing imports, or third-party libraries without proper TypeScript support.
This TypeScript compilation error occurs when TypeScript cannot determine the proper type for a React component and defaults to the "unknown" type. The "FC<Props>" type represents a Function Component with specific props, and TypeScript requires explicit typing for React components to ensure type safety. When you define a React component without proper type annotations or imports, TypeScript may infer it as "unknown" because it cannot determine what the function returns or what props it accepts. This is especially common with: 1. Async components that don't have proper return type annotations 2. Components imported from JavaScript libraries without TypeScript definitions 3. Missing React type imports 4. Complex higher-order components that lose type information The error prevents compilation because "unknown" is TypeScript's safest type - it means "we don't know what this is, so we can't guarantee it's safe to use as a React component." This protects you from runtime errors by catching type issues at compile time.
The simplest fix is to explicitly type your component with React.FC or the FunctionComponent type.
Basic function component:
import React, { FC } from 'react';
interface MyComponentProps {
title: string;
count: number;
}
// Explicitly type the component
const MyComponent: FC<MyComponentProps> = ({ title, count }) => {
return (
<div>
<h1>{title}</h1>
<p>Count: {count}</p>
</div>
);
};
export default MyComponent;Alternative without FC type (explicit return type):
import React, { ReactElement } from 'react';
interface MyComponentProps {
title: string;
}
const MyComponent = ({ title }: MyComponentProps): ReactElement => {
return <h1>{title}</h1>;
};
export default MyComponent;For async components (Next.js App Router, React Server Components):
import React from 'react';
interface PageProps {
params: { id: string };
}
// Async components need explicit Promise<ReactElement> return type
export default async function Page({ params }: PageProps): Promise<React.JSX.Element> {
const data = await fetchData(params.id);
return (
<div>
<h1>{data.title}</h1>
<p>{data.content}</p>
</div>
);
}Many JavaScript libraries don't include TypeScript definitions. You need to install the corresponding @types/ package.
Check if types exist:
# Search for available types
npm search @types/library-name
# Or check DefinitelyTyped repository
# https://github.com/DefinitelyTyped/DefinitelyTypedInstall missing types:
# Install types for a specific library
npm install --save-dev @types/react-router-dom
npm install --save-dev @types/lodash
npm install --save-dev @types/node
# For libraries without official types, you may need to:
# 1. Create a custom declaration file
# 2. Use declare module in your code
# 3. Or add "skipLibCheck": true to tsconfig.json (not recommended)Create custom type declarations:
If a library doesn't have types, create a declaration file (e.g., src/types/custom.d.ts):
// Declare module for JavaScript library
declare module 'untyped-library' {
const value: any;
export default value;
}
// Or provide more specific types
declare module 'custom-react-library' {
import { FC } from 'react';
interface CustomComponentProps {
value: string;
onChange: (value: string) => void;
}
export const CustomComponent: FC<CustomComponentProps>;
export default CustomComponent;
}Ensure your TypeScript configuration supports React and JSX properly.
Required tsconfig.json settings for React:
{
"compilerOptions": {
"jsx": "react-jsx", // or "react" for older versions
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"target": "es5", // or higher
"strict": true,
"esModuleInterop": true,
"skipLibCheck": false, // Keep false for type safety
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true, // For Next.js/Webpack builds
"allowJs": true,
"checkJs": false
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}Common issues and fixes:
1. Missing "jsx" option: Add "jsx": "react-jsx" (React 17+) or "jsx": "react"
2. "skipLibCheck": true: While this suppresses errors, it's better to fix the actual type issues
3. Missing DOM types: Ensure "lib": ["dom", "dom.iterable", "esnext"] includes DOM types
4. Incorrect module resolution: Use "moduleResolution": "node" for Node.js-style imports
5. Missing type roots: Add "typeRoots": ["./node_modules/@types", "./src/types"] for custom types
Missing or incorrect React imports are a common cause of "unknown" type inference.
Essential React imports for TypeScript:
// Basic React imports
import React from 'react';
import { FC, ReactElement, ReactNode, ComponentProps } from 'react';
// For class components (if needed)
import { Component, PureComponent } from 'react';
// Hooks
import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
// Context
import { createContext, useContext, Context } from 'react';
// For Next.js App Router
import type { Metadata } from 'next';Common import mistakes:
// ❌ Missing React import (causes "unknown" type)
const Component = () => <div>Hello</div>;
// ✅ Correct - import React
import React from 'react';
const Component = () => <div>Hello</div>;
// ❌ Using JSX without proper configuration
// Fix: Ensure tsconfig.json has "jsx": "react-jsx"
// ❌ Missing type-only imports
import type { FC } from 'react'; // Type-only import (React 17+)Auto-import configuration:
If your IDE isn't auto-importing React types:
1. VS Code: Install "TypeScript and JavaScript Language Features" extension
2. WebStorm: Enable "TypeScript language service"
3. Ensure node_modules/@types/react is installed: npm list @types/react
Higher-order components, render props, and compound components often lose type information.
Higher-Order Component with proper typing:
import React, { ComponentType } from 'react';
interface WithLoadingProps {
isLoading: boolean;
}
// Generic HOC that preserves component props
function withLoading<P extends object>(
WrappedComponent: ComponentType<P>
): ComponentType<P & WithLoadingProps> {
const WithLoading = (props: P & WithLoadingProps) => {
const { isLoading, ...restProps } = props;
if (isLoading) {
return <div>Loading...</div>;
}
return <WrappedComponent {...restProps as P} />;
};
// Display name for DevTools
WithLoading.displayName = `WithLoading(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
return WithLoading;
}
// Usage
interface UserProfileProps {
name: string;
email: string;
}
const UserProfile: FC<UserProfileProps> = ({ name, email }) => (
<div>
<h2>{name}</h2>
<p>{email}</p>
</div>
);
const UserProfileWithLoading = withLoading(UserProfile);
// Type: ComponentType<UserProfileProps & WithLoadingProps>Render props pattern:
import React, { ReactNode } from 'react';
interface DataProviderProps<T> {
children: (data: T) => ReactNode;
fetchData: () => Promise<T>;
}
function DataProvider<T>({ children, fetchData }: DataProviderProps<T>): ReactElement {
const [data, setData] = useState<T | null>(null);
useEffect(() => {
fetchData().then(setData);
}, [fetchData]);
if (!data) return <div>Loading...</div>;
return <>{children(data)}</>;
}
// Usage with explicit type parameter
<DataProvider<{ id: string; name: string }>
fetchData={() => fetch('/api/user').then(res => res.json())}
>
{(user) => (
<div>
<h1>{user.name}</h1>
<p>ID: {user.id}</p>
</div>
)}
</DataProvider>TypeScript provides utility types that help with React component typing.
Common React type utilities:
import { ComponentProps, ComponentPropsWithoutRef, ComponentPropsWithRef } from 'react';
// Get props from existing component
type ButtonProps = ComponentProps<typeof Button>;
type InputProps = ComponentPropsWithoutRef<'input'>;
type DivProps = ComponentPropsWithRef<'div'>;
// For event handlers
type ClickHandler = React.MouseEventHandler<HTMLButtonElement>;
type ChangeHandler = React.ChangeEventHandler<HTMLInputElement>;
type SubmitHandler = React.FormEventHandler<HTMLFormElement>;
// Children types
type PropsWithChildren<P = unknown> = P & { children?: ReactNode };
type PropsWithoutChildren<P = unknown> = Omit<P, 'children'>;
// Conditional rendering
type ConditionalProps = {
isLoading: boolean;
data: string | null;
error: Error | null;
};
const ConditionalComponent: FC<ConditionalProps> = ({ isLoading, data, error }) => {
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!data) return <div>No data</div>;
return <div>{data}</div>;
};Using generics with FC:
// Generic component
interface ListProps<T> {
items: T[];
renderItem: (item: T) => ReactNode;
}
function List<T>({ items, renderItem }: ListProps<T>): ReactElement {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{renderItem(item)}</li>
))}
</ul>
);
}
// Usage
<List<{ id: number; name: string }>
items={users}
renderItem={(user) => <span>{user.name} (ID: {user.id})</span>}
/>TypeScript strict mode and "unknown":
TypeScript's "unknown" type is the type-safe counterpart of "any". While "any" disables type checking, "unknown" forces you to perform type checks before using the value. In strict mode, TypeScript is more aggressive about inferring "unknown" when it can't determine a type.
Key differences:
- any: "Trust me, I know what I'm doing" - disables type checking
- unknown: "I don't know what this is, prove it's safe" - requires type guards
- never: "This should never happen" - for impossible states
- void: "No meaningful value" - for functions that don't return
React TypeScript best practices:
1. Always type component props explicitly - Don't rely on inference for public APIs
2. Use React.FC for function components - Provides children typing and defaultProps support
3. Type event handlers specifically - Use React.MouseEventHandler instead of (e: any) => void
4. Create custom hooks with explicit return types - Helps with inference in consuming components
5. Use ComponentProps utility types - For wrapping or extending existing components
6. Add displayName to HOCs - Helps with React DevTools debugging
Performance considerations:
Explicit typing doesn't affect runtime performance but improves:
1. Compilation speed - TypeScript can skip inference work
2. IDE performance - Less work for language server
3. Bundle size - Types are stripped in production
Framework-specific notes:
- Next.js: Server Components require Promise<React.JSX.Element> return type for async components
- Vite: Ensure @vitejs/plugin-react is configured with TypeScript
- Create React App: Uses react-scripts which includes TypeScript configuration
- Remix: TypeScript configuration is in remix.config.js
Debugging TypeScript React errors:
1. Use tsc --noEmit to check types without building
2. Add // @ts-expect-error comments with explanations for intentional type violations
3. Use TypeScript Playground to isolate and test type issues
4. Check node_modules/@types/react/index.d.ts for React type definitions
When to use type assertions (as):
Only use type assertions when you know more than TypeScript:
// ❌ Avoid when possible
const component = importedValue as FC<Props>;
// ✅ Better: Type guard function
function isReactComponent(value: unknown): value is FC<Props> {
return typeof value === 'function' &&
value.prototype?.isReactComponent !== undefined;
}
// ✅ Or: Runtime check with error
if (!isReactComponent(importedValue)) {
throw new Error('Expected a React component');
}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