Generic constraints restrict the types that can be used with a generic type parameter using the extends keyword. They ensure that the type provides specific properties or methods required by the code.

- Restrict the types that can be used with generics.
- Use extends to define the required structure.
- Allow safe access to specific properties or methods.
- Catch invalid type usage at compile time.
Syntax:
function functionName<T extends Constraint>(value: T): void {
// Function body
}
- T: The generic type parameter.
- extends: Restricts T to types that satisfy the specified constraint.
- Constraint: The type, interface, or structure that T must satisfy.
Examples of Generic Constraints in TypeScript
The following examples demonstrate how generic constraints restrict types and provide access to required properties or methods.
Example 1: Constraint with an Interface
A generic constraint can require an argument to contain specific properties.
interface Sports {
name: string;
}
function printSportName<T extends Sports>(sport: T): void {
console.log(sport.name);
}
const sport: Sports = {
name: "Baseball"
};
printSportName(sport);
Output:
Baseball- T extends Sports requires T to have a name property.
- The function can safely access sport.name.
Example 2: Constraint with keyof
The keyof operator can restrict a generic parameter to valid property keys of another type.
interface Sports {
name: string;
players: number;
}
function getProperty<T, K extends keyof T>(sport: T, key: K): T[K] {
return sport[key];
}
const sport: Sports = {
name: "Baseball",
players: 9
};
const players = getProperty(sport, "players");
console.log(`Number of Players: ${players}`);
Output:
Number of Players: 9- K extends keyof T restricts K to valid keys of T.
- "players" is a valid key of Sports.
- T[K] represents the type of the selected property.
Example 3: Constraint with an Interface and Class
A generic constraint can require an object to provide specific properties and methods.
interface Sports {
name: string;
players: number;
getNumberOfGloves(): number;
}
class Baseball implements Sports {
constructor(
public name: string,
public players: number
) {}
getNumberOfGloves(): number {
return this.players * 2;
}
}
function getNumberOfGloves<T extends Sports>(sport: T): void {
console.log(
`Number of Gloves Required: ${sport.getNumberOfGloves()}`
);
}
const baseball = new Baseball("Baseball", 9);
getNumberOfGloves(baseball);
Output:
Number of Gloves Required: 18- Sports defines the required properties and method.
- Baseball implements the Sports interface.
- T extends Sports ensures that only compatible objects can be passed to getNumberOfGloves().