Generics allow creating reusable components that work with multiple types while maintaining type safety. They use type parameters (like <T>) that are specified when the component is used, enabling type inference and constraints.
What Generics Do:
any and losing type safetyGeneric Syntax:
<T> (can be any name)<T, U, K><T extends SomeType><T = DefaultType>Where to Use:
// Without generics - lose type information
function firstAny(arr: any[]): any {
return arr[0];
}
const result = firstAny([1, 2, 3]); // type: any
// With generics - preserve type
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
const num = first([1, 2, 3]); // type: number
const str = first(['a', 'b']); // type: string
const user = first([{ name: 'Alice' }]); // type: { name: string }
// Multiple type parameters
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
const p = pair('hello', 42); // type: [string, number]
// Generic with inference
function map<T, U>(arr: T[], fn: (item: T) => U): U[] {
return arr.map(fn);
}
const lengths = map(['hello', 'world'], s => s.length);
// lengths: number[] (inferred!)