After this lesson, you will be able to: Use generics: functions, classes, interfaces, constraints, default type parameters.
Generics are the type-level functions. Mastering them unlocks 80% of advanced TS.
Functions that preserve type.
// Without generic, loses typefunction firstAny(arr: any[]): any { return arr[0]; }// With generic, preservesfunction first<T>(arr: T[]): T | undefined {return arr[0];}const x = first([1, 2, 3]); // number | undefinedconst y = first(["a", "b"]); // string | undefinedconst z = first<string>([]); // explicit// Multiple genericsfunction pair<A, B>(a: A, b: B): [A, B] { return [a, b]; }// Constraintfunction longest<T extends { length: number }>(a: T, b: T): T {return a.length >= b.length ? a : b;}longest("abc", "defg"); // oklongest([1, 2], [3, 4, 5]); // oklongest(1, 2); // Error, number has no length
Same shape; type carried through.
// Generic interfaceinterface Box<T> {value: T;unwrap(): T;}const boxNum: Box<number> = { value: 42, unwrap() { return this.value; } };// Generic classclass Stack<T> {private items: T[] = [];push(item: T) { this.items.push(item); }pop(): T | undefined { return this.items.pop(); }}const s = new Stack<string>();s.push("a");
Provide a fallback when caller doesn't specify.
type Result<T, E = Error> = { ok: true; data: T } | { ok: false; error: E };// Most uses: Result<User>, E defaults to Error// Custom error type: Result<User, ApiError>
Generics that aren't actually used, `<T>` parameters that never appear. Replace with concrete type. Over-constrained generics that don't need the constraint. Forgetting that TS infers generics from arguments. `first([1, 2])` auto-infers T=number; don't always write `first<number>([1, 2])`. Generic parameters with cryptic names. T is convention; for >1 generic, use semantic names: `Map<K, V>`, not `Map<T, U>`.
Pick the cleanest answer.
Sign in and purchase access to unlock this lesson.