Hint
extends limits which types a type parameter can be — ensures the type has the properties you need
Generic constraints restrict a type parameter to a subset of types using extends. This lets you access properties guaranteed to exist.
// Without constraint — T could be anything
function getLength<T>(val: T) {
return val.length; // ❌ Error — T might not have .length
}
// With constraint — T must have .length
function getLength<T extends { length: number }>(val: T): number {
return val.length; // ✅ Safe
}
getLength('hello'); // string has .length
getLength([1, 2, 3]); // array has .length
getLength(42); // ❌ Error — number has no .length
keyof constraint — ensures a key exists on an object:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]; // type-safe property access
}
const user = { name: 'Alice', age: 30 };
getProperty(user, 'name'); // returns string
getProperty(user, 'age'); // returns number
getProperty(user, 'email'); // ❌ Error — 'email' not in user
Multiple constraints:
// Intersection for multiple requirements
function merge<T extends object, U extends object>(a: T, b: U): T & U {
return { ...a, ...b };
}
// Constraint with another type parameter
function copyFields<T extends U, U>(target: T, source: U): T {
return Object.assign(target, source);
}
<T extends keyof U> is one of the most powerful in TypeScript — it lets you write utilities like Omit, Pick, and getProperty that are fully type-safe at the call site.