Generics
~320 words ยท 2 min read
Generics in TypeScript
Generics let you write code that works across a range of types while preserving type safety. They are the key to reusable, type-correct functions and data structures.
The Problem Generics Solve
Without generics, a function that returns its input is either untyped (any) or duplicated for every type. A generic captures the type once and carries it through the function.
function identity<T>(value: T): T {
return value;
}
const n = identity(42); // n is number
const s = identity("hi"); // s is string
Generic Functions
The type parameter T (or any name) is a placeholder filled in at the call site. TypeScript usually infers it from the argument.
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
first([1, 2, 3]); // number | undefined
first(["a", "b"]); // string | undefined
Generic Constraints
Sometimes a generic must satisfy a contract. The extends keyword constrains the type parameter so you can safely access specific properties.
function getLength<T extends { length: number }>(x: T): number {
return x.length; // OK: T is guaranteed to have length
}
getLength("hello"); // 5
getLength([1, 2, 3]); // 3
Constraints turn a loose generic into a precise contract.
<T extends { length: number }>says "any type T, as long as it has a numeric length property" โ safe and flexible at once.
Utility Types
TypeScript ships built-in generic types that transform other types. The most common are Partial, Pick, and Omit.
interface User {
id: number;
name: string;
email: string;
}
type UserPatch = Partial<User>; // every property optional
type UserName = Pick<User, "id" | "name">; // only id and name
type PublicUser = Omit<User, "email">; // drops email
Partial<T> makes every property optional; Pick<T, K> selects a subset of keys; Omit<T, K> removes keys. Together they let you derive new types from existing ones without repetition.