extends in generic parameters
1. General form
javascript
function example<T extends Constraint>(value: T) { ... }Tis the type parameter (generic).extends Constraintis the constraint thatTmust satisfy.
TypeScript checks whether T can be considered a subtype of Constraint.
If not, the compiler throws an error.
Example 1: a shape constraint
javascript
function printLength<T extends { length: number }>(value: T) {
console.log(value.length);
}
printLength("hello"); // a string has length
printLength([1, 2, 3]); // an array has length
printLength(123); // a number does not have lengthHere
Tmust be a type that has alength: numberproperty.
Example 2: a base-type constraint
javascript
function toStringValue<T extends string | number>(value: T): string {
return value.toString();
}
toStringValue("abc"); // string
toStringValue(123); // number
toStringValue(true); // boolean is not part of the allowed unionHere
Tis constrained by the union:string | number.
Example 3: an interface constraint
javascript
interface Identifiable {
id: string;
}
function logId<T extends Identifiable>(obj: T) {
console.log(obj.id);
}
logId({ id: "123", name: "Tim" }); // OK
logId({ name: "Alex" }); // missing id
Tis required to contain anidfield.
Example 4: dependent generic parameters
javascript
function getProp<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const user = { id: 1, name: "Tim" };
getProp(user, "id"); // OK
getProp(user, "age"); // "age" is not a key of userHere
Kdepends onTand is constrained to only the object's allowed keys.
Example 5: a constraint for classes and constructors
javascript
type Constructor<T> = new (...args: any[]) => T;
function createInstance<T extends Constructor<any>>(Ctor: T) {
return new Ctor();
}
Tmust be a constructor (a class) so that it can be instantiated vianew.
Example 6: a constraint for dictionaries (Record)
javascript
function sumValues<T extends Record<string, number>>(obj: T): number {
return Object.values(obj).reduce((a, b) => a + b, 0);
}
sumValues({ a: 1, b: 2 }); // OK
sumValues({ x: 1, y: "two" }); // a string, not number
Record<string, number>means: an object whose keys are strings and values are numbers.
Example 7: extends + a default value
javascript
function identity<T extends string | number = string>(value: T): T {
return value;
}
identity("hi"); // OK
identity(42); // OK
identity(true); // boolean does not satisfy the constraintWhat extends actually does in generic parameters
- Constrains the substitutable type -
Tmust extend (be a subtype of) the given type. - Guarantees properties - you can access them without errors.
- Improves type inference - TS knows more about the possible structure of
T. - Does not create inheritance! - it is not the
extendsfrom classes, but a logical type constraint.
Example without extends -> an error
javascript
function getLength<T>(value: T): number {
return value.length; // TS Error: T might not have length
}Fixed:
javascript
function getLength<T extends { length: number }>(value: T) {
return value.length; // OK
}Summary
Purpose of extends | Example | What it provides |
|---|---|---|
| Shape constraint | <T extends { id: string }> | Guarantees the presence of fields |
| Union constraint | <T extends string | number> | Only the listed types |
| Interface constraint | <T extends Identifiable> | Only types that implement the interface |
| Parameter dependency | <K extends keyof T> | The key must belong to the object |
| Class constraint | <T extends new (...args) => any> | Only constructors |
| Dictionary constraint | <T extends Record<string, number>> | Objects with a defined value type |
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.