On this Page
Why Use Constraints?
Without constraints, generic types can be anything β even things that donβt support the operations you want.
function getLength<t>(value: T): number {
return value.length; // β Error: T might not have `.length`
}
We can fix this with a constraint.
Using extends to Restrict Generics
You can require that a generic extends a base type:
function getLength<t extends length: number>(value: T): number {
return value.length;
}
Now the function works only with types that have a .length property:
getLength("hello"); // β
getLength([1, 2, 3]); // β
getLength(123); // β Error
Accessing Object Properties Safely
You can ensure that a key exists on an object using keyof:
function getProp<t k extends keyof t>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Lior", age: 30 };
getProp(user, "name"); // "Lior"
getProp(user, "email"); // β Error: Property does not exist
This makes your generic functions type-safe and self-validating.
Default Type Parameters
You can provide a default if the caller doesnβt supply one:
type ApiResponse<t any> = {
data: T;
error?: string;
};
const res: ApiResponse = {
data: "fallback type is any",
};
This is useful for utilities or when you want to provide a sensible fallback.
Combining Constraints and Defaults
You can use both together:
function identity<t extends string number="string">(value: T): T {
return value;
}
identity("test"); // ok
identity(123); // ok
identity(true); // β Error: boolean not allowed
Summary
- Use
extendsto restrict generics to specific shapes or types - Use
keyofand indexed types to safely access object properties - Provide default types for simpler usage and better fallback
- Combining constraints and defaults gives you control and flexibility
Next up: Lesson 13 β Utility Types: Partial, Pick, Omit, and Record β learn how to transform types like a pro.