Generics are TypeScript's most powerful feature. At Google, we use them everywhere — from API clients to state management to utility types.
Why Generics?
Generics let you write reusable code that maintains type safety. Without them, you'd need to write separate functions for each type or use any.
// Without generics
function first(arr: any[]): any { return arr[0]; }
// With generics
function first<T>(arr: T[]): T { return arr[0]; }
first([1, 2, 3]); // TypeScript infers T = numberConstraints
interface HasLength { length: number; }
function logLength<T extends HasLength>(item: T): T {
console.log(item.length);
return item;
}
logLength("hello"); // OK
logLength([1, 2]); // OK
logLength(42); // Error: number has no lengthAdvanced Patterns
Conditional Types
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
// Practical: Extract promise value
type Unwrap<T> = T extends Promise<infer U> ? U : T;
type X = Unwrap<Promise<string>>; // stringMapped Types
type Readonly<T> = { readonly [K in keyof T]: T[K] };
type Optional<T> = { [K in keyof T]?: T[K] };
type Nullable<T> = { [K in keyof T]: T[K] | null };Template Literal Types
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<"click">; // "onClick"
type CSSProperty = `${string}-${string}`;
const valid: CSSProperty = "font-size"; // OKCommon Mistakes
- Over-constraining: Don't add constraints you don't need
- Generic soup: If you have 4+ type parameters, refactor
- Using
anyinside generics defeats the purpose — useunknown