This error occurs when a React component receives a prop whose type does not match the expected type definition, either through PropTypes validation or TypeScript type checking. It indicates a mismatch between what the component expects and what is actually being passed.
This error appears in two main contexts in React development: when using PropTypes for runtime validation or when using TypeScript for compile-time type checking. In PropTypes-based projects, this manifests as a console warning in development mode when a prop's actual type doesn't match its PropTypes definition. For example, passing a string "123" when PropTypes.number is expected will trigger this warning. In TypeScript projects, this is a compile-time error that prevents your code from building. TypeScript checks that every prop passed to a component matches its type definition exactly. This can occur with basic type mismatches (string vs number), missing required props, or incompatible complex types (objects, arrays, unions). The error serves as a safety mechanism to catch bugs early—before they reach production—by ensuring components receive the correct data types they're designed to handle. While PropTypes only warns at runtime in development, TypeScript prevents compilation entirely, making it a more robust solution for type safety.
Check the error message to identify which prop and component are involved:
Failed prop type: Invalid prop `count` of type `string`
supplied to `Counter`, expected `number`For TypeScript errors, the compiler will show:
Type 'string' is not assignable to type 'number'Look at both the component definition and where it's being used to understand the mismatch.
For PropTypes, verify the prop definition in the component:
import PropTypes from 'prop-types';
function Counter({ count }) {
return <div>Count: {count}</div>;
}
Counter.propTypes = {
count: PropTypes.number.isRequired, // Expects number
};For TypeScript, check the interface or type definition:
interface CounterProps {
count: number; // Expects number
}
function Counter({ count }: CounterProps) {
return <div>Count: {count}</div>;
}Convert the value to the correct type when passing it:
Wrong:
<Counter count="42" /> {/* String instead of number */}Correct:
<Counter count={42} /> {/* Number */}For dynamic values, convert them explicitly:
const countStr = "42";
<Counter count={Number(countStr)} />
// or
<Counter count={parseInt(countStr, 10)} />For optional props, handle undefined cases:
<Counter count={maybeCount ?? 0} />If the component should actually accept multiple types, update the definition:
PropTypes with multiple types:
Counter.propTypes = {
count: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]).isRequired,
};TypeScript union types:
interface CounterProps {
count: string | number;
}Make props optional:
interface CounterProps {
count?: number; // Optional with ?
}
// Or with PropTypes:
Counter.propTypes = {
count: PropTypes.number, // Not required
};For objects and arrays, ensure the structure matches:
Wrong:
interface User {
id: number;
name: string;
email: string;
}
// Missing email property
<UserCard user={{ id: 1, name: "John" }} />Correct:
<UserCard user={{ id: 1, name: "John", email: "[email protected]" }} />For complex validation, use custom PropTypes:
Counter.propTypes = {
user: PropTypes.shape({
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
email: PropTypes.string.isRequired,
}).isRequired,
};PropTypes vs TypeScript: PropTypes provide runtime validation only in development mode and are stripped in production builds. TypeScript provides compile-time type safety but doesn't check types at runtime. Many modern React projects use TypeScript exclusively and remove PropTypes entirely. However, some projects use both for defense-in-depth, where TypeScript catches errors during development and PropTypes catch errors from external data sources or dynamically loaded code.
Type Coercion Pitfalls: JavaScript's loose typing can mask type issues. For example, passing "42" to a component expecting a number might not immediately fail because many operations work on both strings and numbers. However, operations like arithmetic will produce unexpected results ("42" + 1 = "421" instead of 43). Always be explicit with types in React props.
Generic Components: When building generic components with TypeScript, use proper type constraints to ensure props match expected patterns. Inference can fail in complex scenarios, requiring explicit type parameters: <DataList<User> items={users} />.
defaultProps Deprecation: In React 18+, defaultProps is deprecated for function components. Use default parameter values instead: function Counter({ count = 0 }: CounterProps). This provides better TypeScript inference and aligns with modern JavaScript patterns.
ESLint Integration: The react/prop-types ESLint rule can detect missing PropTypes definitions. In TypeScript projects, you can safely disable this rule in your ESLint config since TypeScript provides superior type checking. Add "react/prop-types": "off" to your rules configuration.
Debugging Tips: When facing type mismatches in large component trees, use React DevTools to inspect the actual prop values being passed at runtime. Compare these with your type definitions to identify where the mismatch originates. For TypeScript errors, use // @ts-expect-error comments temporarily to isolate the problematic prop while fixing it.
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