Generic Constraints
Why generic constraints are necessary
Generics provide flexibility, but unlimited flexibility can reduce safety. Sometimes you need to ensure that a generic type follows certain rules, such as having specific properties or extending a base type. Generic constraints allow you to restrict what types can be used.
The problem without constraints
Consider a function that tries to access a property on a generic value.
function getLength(value: T): number { return value.length; // Error }
The compiler does not know that T has a length property. Without constraints, this is unsafe.
Using extends to constrain types
You can restrict a generic type using the extends keyword.
function getLength(value: T): number { return value.length; } getLength("Hello"); // OK getLength([1, 2, 3]); // OK // getLength(42); // Error
Now T must have a length property.
Constraining to interfaces
You can constrain generics to a specific interface.
interface Identifiable {
id: number;
}
function printId(item: T): number {
return item.id;
}
This ensures that any type passed into the function includes an id field.
Constraining with keyof
You can restrict one generic type parameter based on another.
function getProperty(obj: T, key: K) { return obj[key]; } const user = { id: 1, name: "Ozan" }; getProperty(user, "name"); // OK // getProperty(user, "age"); // Error
This pattern is common in reusable utility functions.
Multiple constraints
Generics can be constrained by complex type relationships.
function merge(a: T, b: U): T & U { return { ...a, ...b }; }
Here, both type parameters must be objects.
Why constraints scale
Constraints allow you to write reusable abstractions without sacrificing correctness. In production systems, this is essential when designing reusable libraries, repository patterns, and service layers.
Common mistakes
- Leaving generics unconstrained when assumptions exist.
- Over-constraining types and reducing flexibility unnecessarily.
- Using any instead of defining proper structural constraints.
Production guidance
- Always constrain generics when you rely on specific properties.
- Use keyof patterns for safe property access utilities.
- Keep constraints readable and meaningful.
- Balance flexibility with architectural clarity.
What’s next
Now that you understand how to restrict generic types, the next step is exploring utility types that transform and compose existing types efficiently.