1. Introduction
By default, a generic type parameter T can be absolutely anything, which means the compiler will not let you assume T has any particular property or method. Generic constraints solve this by restricting what types are acceptable for a type parameter using the extends keyword, so you can rely on a minimum shape while still keeping the parameter generic.
Cricket analogy: Without a constraint, a generic T could be a bat, a ball, or a scoreboard — the compiler can't assume any of them has an 'average' property; T extends { average: number } guarantees at least that minimum shape while still accepting any player-like type.
2. Syntax
// Constrain T to anything with a numeric length property
function logLength<T extends { length: number }>(value: T): T {
console.log(value.length);
return value;
}
// Constrain T to a specific interface
interface HasId {
id: number;
}
function printId<T extends HasId>(item: T): void {
console.log(item.id);
}
// Constrain K to the keys of T
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
// Default type parameter combined with a constraint
function createList<T extends object = {}>(items: T[] = []): T[] {
return items;
}3. Explanation
Generic constraints with extends restrict what types are acceptable for a type parameter — for example T extends { length: number } means only types that have a numeric length property (arrays, strings, and any custom object with length) can be passed as T. This lets the function body safely access value.length without the compiler complaining that length might not exist, while still allowing many different concrete types to satisfy the constraint.
Cricket analogy: T extends { length: number } accepts a batting lineup array or a player's name string because both have a numeric length, letting a function safely read value.length to count how many batters like Rohit Sharma's top order remain.
The most powerful constraint pattern combines keyof with generics for type-safe property access: function getProp<T, K extends keyof T>(obj: T, key: K): T[K]. Here keyof T produces a union of T's own property names, and constraining K to that union guarantees key really exists on obj — attempting to call getProp(obj, "nonexistentKey") is a compile-time error, not a runtime surprise.
Cricket analogy: function getStat<T, K extends keyof T>(player: T, stat: K): T[K] guarantees stat is a real property of a Player object like Kohli's, so calling getStat(player, "battingAverage") works but getStat(player, "golfHandicap") fails at compile time.
Constraints can also be interfaces or classes (T extends HasId), unions, or even other type parameters (function copyProps<T, U extends T>(target: T, source: U)), and can be paired with default type parameters (T extends object = {}) so callers can omit the type argument entirely for the common case.
Cricket analogy: T extends HasId could constrain a generic function to any Player or Umpire interface with an ID field, while function copyProps<T, U extends T>(target: T, source: U) ensures you only copy stats from a batter's extended profile onto their base profile, never the reverse.
Gotcha: a common misconception is that T extends { length: number } means T IS a { length: number } object — it actually means T is any type that is assignable to (a subtype of, or compatible with) that shape, so string, number[], and custom classes with a length field are all valid. Also, logLength<T extends { length: number }> does not restrict the return type to only length — the full shape of T is preserved on the way out.
4. Example
function logLength<T extends { length: number }>(value: T): T {
console.log(`length: ${value.length}`);
return value;
}
interface HasId {
id: number;
}
function printId<T extends HasId>(item: T): void {
console.log(`id: ${item.id}`);
}
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
logLength("hello"); // string has .length
logLength([1, 2, 3, 4]); // array has .length
printId({ id: 7, name: "Widget" }); // extra props are fine
const product = { id: 99, price: 250, name: "Keyboard" };
console.log(getProp(product, "price"));
// Compile errors (uncomment to see):
// logLength(42); // number has no .length
// getProp(product, "weight"); // 'weight' is not a key of product5. Output
length: 5
length: 4
id: 7
2506. Key Takeaways
Practice what you learned
1. What does the constraint in `function logLength<T extends { length: number }>(value: T): T` actually mean?
2. What is the purpose of `K extends keyof T` in `function getProp<T, K extends keyof T>(obj: T, key: K): T[K]`?
3. Given `logLength(42)` where `logLength<T extends { length: number }>(value: T): T`, what happens?
4. Can a generic constraint reference another type parameter, as in `function copyProps<T, U extends T>(target: T, source: U)`?
5. Why is `printId({ id: 7, name: "Widget" })` valid when `printId<T extends HasId>(item: T)` and `HasId` only declares `id: number`?
Was this page helpful?
You May Also Like
Generics in TypeScript
Learn how TypeScript generics let you write reusable, type-safe code that works across many types without losing type information.
Generic Functions in TypeScript
Learn how to write and call generic functions in TypeScript, including type inference, explicit type arguments, and multi-parameter generics.
keyof and typeof Operators in TypeScript
Use `keyof T` to get a union of a type's property names, and `typeof x` in a type position to extract the type of a value.
Extending Interfaces in TypeScript
Learn how the `extends` keyword lets one interface inherit and build upon the members of one or more other interfaces.
Conditional Types in TypeScript
Branch at the type level with `T extends U ? X : Y`, including how distributive conditional types behave over union types.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics