Generics
Write functions and types that work with any type while keeping type safety.
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
first([1, 2, 3]); // number | undefined
first(["a", "b"]); // string | undefined
The <T> is a type parameter. TypeScript infers it from the argument, so you rarely need to specify it.
Constrained Generics
Limit what types are accepted:
function getLength<T extends { length: number }>(item: T): number {
return item.length;
}
getLength("hello"); // OK - strings have length
getLength([1, 2, 3]); // OK - arrays have length
getLength(42); // Error - numbers don't have length
Generic Interfaces and Types
interface Response<T> {
data: T;
status: number;
error?: string;
}
type UserResponse = Response<User>;
type ListResponse = Response<User[]>;
Multiple Type Parameters
function merge<T extends object, U extends object>(a: T, b: U): T & U {
return { ...a, ...b };
}
const result = merge({ name: "Alice" }, { age: 30 });
// result: { name: string; age: number }
Tip: Name type parameters meaningfully when you have more than one:
<TKey, TValue>is clearer than<K, V>in complex code.