TypeScript Generics
Reusable, type-safe code with generics
What you'll learn
Understand generics as type parameters that capture argument types
Write generic functions and interfaces with type variables
Constrain generics with extends to limit acceptable types
Build reusable utility types using generic constraints
Use conditional types with infer for type transformations
Apply mapped types to transform existing types
Generics let you write code that works with any type while preserving type safety.
Generic Functions
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
Generic Constraints
interface HasId {
id: string
}
function getById<T extends HasId>(items: T[], id: string): T | undefined {
return items.find((item) => item.id === id)
}
Generic Components (React)
interface ListProps<T> {
items: T[]
renderItem: (item: T) => React.ReactNode
}
function List<T>({ items, renderItem }: ListProps<T>) {
return <ul>{items.map(renderItem)}</ul>
}
// Usage — type inferred from items
;<List items={users} renderItem={(user) => <li>{user.name}</li>} />
Next Steps
Key Takeaways
Generics capture the type of an argument and carry it through function returns, exactly like a type variable
Generic constraints (extends) limit what types are accepted while preserving the actual type
Generic interfaces and types create reusable abstractions that work with many concrete types
Conditional types (T extends U ? X : Y) select types based on conditions at the type level
The infer keyword in conditional types extracts and captures a type from a larger type pattern