Back to Blog
TypeScript2026-04-25

TypeScript Generics Mastery

Move beyond Array<T> and learn the patterns that make TypeScript libraries elegant.

Generics are the lever that lets one function or type work across many shapes without losing safety. The basics are easy. The leverage is in constraints, conditional types, and inference.

Constrained Generics

``ts function pluck(obj: T, keys: K[]): Pick { return keys.reduce((acc, key) => { acc[key] = obj[key]; return acc; }, {} as Pick); } `

The K extends keyof T constraint ensures only valid keys are passed.

Inference From Function Arguments

`ts function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C): C { return bc(ab(a)); } `

TypeScript infers all three type parameters from the call site. Users never write angle brackets.

Conditional Types

`ts type Awaited = T extends Promise ? U : T; `

The infer keyword extracts a type from a position. This powers utilities like ReturnType and Parameters.

Variadic Tuples

`ts type Last = T extends [...unknown[], infer L] ? L : never; `

Variadic tuples (TS 4.0+) let you describe head/tail patterns previously impossible.

Branded Types

`ts type UserId = string & { readonly __brand: 'UserId' }; function asUserId(s: string): UserId { return s as UserId; } `

A regular string no longer fits where UserId` is required, catching wrong-ID-passed-to-function bugs at compile time.

When to Stop

Generics that need three lines of conditionals to read are usually a sign you should split the type. Aim for the simplest signature your callers can ignore.

For practical TypeScript in tests, see [testing with vitest 2026](/blog/testing-with-vitest-2026).