You are viewing a free preview of this lesson.
Subscribe to unlock all 12 lessons in this course and every other course on LearningBro.
Generics allow you to write flexible, reusable components that work with a variety of types rather than a single one — without sacrificing type safety. They are one of TypeScript's most powerful features and are used extensively in libraries, frameworks, and everyday application code.
Without generics, you would have to choose between writing type-safe code that only works with one type, or using any and losing type safety entirely:
// Too restrictive — only works with numbers
function firstNumber(arr: number[]): number {
return arr[0];
}
// Too loose — no type safety
function firstAny(arr: any[]): any {
return arr[0];
}
// Just right — generic
function first<T>(arr: T[]): T {
return arr[0];
}
const name = first(['Alice', 'Bob']); // string
const num = first([1, 2, 3]); // number
Declare a type parameter in angle brackets before the parameter list:
function identity<T>(value: T): T {
return value;
}
// TypeScript infers T from the argument:
const str = identity('hello'); // string
const num = identity(42); // number
// Or specify explicitly:
const bool = identity<boolean>(true);
You can use multiple type parameters:
function pair<A, B>(first: A, second: B): [A, B] {
return [first, second];
}
const result = pair('age', 30); // [string, number]
Interfaces can be parameterised with generic types:
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
interface User {
id: number;
name: string;
}
const response: ApiResponse<User> = {
data: { id: 1, name: 'Alice' },
status: 200,
message: 'OK',
};
const listResponse: ApiResponse<User[]> = {
data: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }],
status: 200,
message: 'OK',
};
Sometimes you need to restrict what types a generic can accept. Use the extends keyword:
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(item: T): void {
console.log(`Length: ${item.length}`);
}
logLength('hello'); // OK — string has .length
logLength([1, 2, 3]); // OK — array has .length
// logLength(42); // Error: number has no .length
A common pattern is to constrain a generic to the keys of another type:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { id: 1, name: 'Alice', age: 30 };
Subscribe to continue reading
Get full access to this lesson and all 12 lessons in this course.