This error occurs when a type argument passed to a generic function or type does not meet the constraint defined with the extends keyword. It happens when TypeScript cannot verify that the provided type has the required properties or structure.
The "Type does not satisfy the constraint" error appears when you use TypeScript generics with constraints, but the type you're trying to use doesn't match what the constraint requires. Generic constraints use the `extends` keyword to specify that a type parameter must have certain properties or extend a particular type. For example, if you define a function with `<T extends number>` but try to pass a string, TypeScript will reject it because string doesn't satisfy the number constraint. This error is TypeScript's way of enforcing type safety at compile time, preventing runtime errors where code expects certain properties or behaviors that the actual type doesn't provide. The error commonly appears in functions with generic constraints, mapped types, utility types, and when working with libraries that use advanced generic patterns like React Navigation or Redux.
First, examine what constraint is being enforced. Look for the extends keyword in the generic declaration:
// The constraint here requires T to extend number
function double<T extends number>(value: T): T {
return (value * 2) as T;
}
// This will fail: Type 'string' does not satisfy the constraint 'number'
double<string>("5");Identify what type or interface the generic parameter must extend.
Ensure the type argument you're providing actually satisfies the constraint:
// Correct: number satisfies the constraint
double<number>(5); // ✓ Works
// If you need to work with strings, change the constraint
function doubleValue<T extends number | string>(value: T): T {
if (typeof value === 'number') {
return (value * 2) as T;
}
return (parseInt(value) * 2).toString() as T;
}The type must be assignable to the constraint type.
If the constraint requires specific properties, ensure your type includes them:
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): void {
console.log(arg.length);
}
// Error: Type 'number' does not satisfy the constraint 'Lengthwise'
logLength(3);
// Fix: Use a type that has the length property
logLength("hello"); // ✓ string has length
logLength([1, 2, 3]); // ✓ array has length
logLength({ length: 10 }); // ✓ object with length propertyIf you know a type satisfies the constraint but TypeScript can't infer it, use type assertions:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const obj = { a: 1, b: 2, c: 3 };
// If key is dynamic and TypeScript can't infer it
const dynamicKey = getUserInput(); // returns string
// Use type assertion if you're certain it's valid
getProperty(obj, dynamicKey as keyof typeof obj);
// Or use a type guard
if (dynamicKey in obj) {
getProperty(obj, dynamicKey as keyof typeof obj);
}If the constraint is too restrictive, broaden it to accept the types you need:
// Too restrictive
function process<T extends string>(value: T): void {
console.log(value.toUpperCase());
}
// More permissive - accepts string or number
function process<T extends string | number>(value: T): void {
console.log(String(value).toUpperCase());
}
// Or use a union constraint for objects
type HasId = { id: string | number };
function getId<T extends HasId>(item: T): string | number {
return item.id;
}Sometimes TypeScript can correctly infer the type if you don't explicitly specify it:
function merge<T extends object, U extends object>(obj1: T, obj2: U) {
return { ...obj1, ...obj2 };
}
// Instead of explicitly providing types
merge<{ a: number }, { b: string }>({ a: 1 }, { b: "hello" });
// Let TypeScript infer
merge({ a: 1 }, { b: "hello" }); // TypeScript infers correctlyType inference often works better than manual type arguments in generic functions.
Constraint Complexity: When working with mapped types or conditional types, TypeScript's constraint checking can become complex. The compiler may not always be able to prove that a mapped type satisfies a constraint even when it logically does. In these cases, consider using type assertions or restructuring your types.
Variance Issues: Constraints can interact with TypeScript's variance rules in unexpected ways. Covariance and contravariance affect whether a type satisfies a constraint, especially with function types and method signatures.
The `keyof` Constraint Pattern: A common pattern is <T, K extends keyof T>, which ensures K is a valid key of T. This is extremely useful for type-safe property access and is used throughout the TypeScript ecosystem.
Multiple Constraints: You can use intersection types in constraints: <T extends TypeA & TypeB>. The type must satisfy both constraints simultaneously.
Branded Types: Sometimes constraint errors appear when using branded or nominal types. These are types that are structurally identical but semantically different, which can cause constraint mismatches even when the shapes match.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript