Generic Constraints
Learn how to restrict a generic type parameter to types with specific properties using extends.
Reading Time
16 min
Lesson
Lesson 20 of 30
The Problem: Unconstrained Generics
A plain generic type parameter T could be anything, so TypeScript won’t let you access any properties on it — even ones that seem obviously safe, like .length.
An Unconstrained Generic Fails
function printLength<T>(value: T) {
console.log(value.length); // Error: Property 'length' does not exist on type 'T'
}Constraining with extends
Adding extends after the type parameter restricts T to types that satisfy a given shape, unlocking access to the properties that shape guarantees.
A Constrained Generic
interface HasLength {
length: number;
}
function printLength<T extends HasLength>(value: T) {
console.log(value.length); // OK — T is guaranteed to have 'length'
}
printLength("hello"); // OK — strings have .length
printLength([1, 2, 3]); // OK — arrays have .length
printLength(42); // Error: number doesn't have .lengthConstraining to keyof Another Type
A very common pattern constrains one generic parameter to be a key of another, guaranteeing safe, typed property access — this is exactly how the built-in Object methods stay type-safe.
A Typed getProperty Function
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 30 };
getProperty(user, "name"); // OK, returns a string
getProperty(user, "email"); // Error: 'email' is not a key of the user objectDefault Type Parameters
A generic parameter can have a default type, used when the caller doesn’t explicitly provide or infer one.
Default Generic Type
interface ApiResponse<T = unknown> {
data: T;
success: boolean;
}
const response: ApiResponse = { data: "anything", success: true }; // T defaults to unknownConstraints Narrow, They Don’t Widen
A constraint only guarantees the minimum shape T must have — the actual type passed in can still have additional properties beyond what the constraint requires.
Best Practice
Reach for constraints as soon as a generic function needs to access any property on its parameter. The keyof pattern (T, K extends keyof T) is especially useful for writing safe, reusable object utilities.