BeCuriouzBeCuriouz

Learn something new every day

🔷 TypeScript
🔒

Generic Constraints: Teaching Generics Their Limits

💡 Use T extends U to require that a type parameter has a certain shape, so you can safely use its members while staying generic.

In the last card, a generic like accepted any type. That flexibility comes at a price: inside the function, TypeScript knows nothing about T, so you can't safely touch any properties. Try function len(x: T) { return x.length } and you get an error — T might be a number, which has no .length.

A generic constraint fixes this with the extends keyword. Writing means "T can be any type, as long as it's assignable to U." It narrows the field of allowed types while still staying generic. Now the compiler knows every T has at least the shape of U:

ts
function len<T extends { length: number }>(x: T): number {
  return x.length; // ✅ every T is guaranteed to have .length
}

len("hello");      // 5  — string has length
len([1, 2, 3]);    // 3  — array has length
len(42);           // ✗ Error: number has no 'length'

Crucially, extends here constrains without widening. len("hello") still returns the specific type you passed — the constraint only gates what's allowed in, it doesn't collapse T down to { length: number }. A classic use is keying into objects: guarantees the key actually exists on the object.

ts
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
const user = { name: "Ada", age: 36 };
getProp(user, "age");   // number
getProp(user, "email"); // ✗ Error: "email" is not a key of user
🔒 Generic Constraints: Teaching Generics Their Limits — BeCuriouz