TypeScript Fundamentals
Generics
Generics let types depend on other types. They preserve relationships between inputs, outputs, containers, callbacks, and API shapes without giving up reuse.
- Generics preserve relationships
- Type parameters should appear more than once
- Constraints express required capabilities
- Inference usually fills type arguments
- Generics can become API surface area
function first<T>(items: T[]): T | undefined {
return items[0]
}
const a = first([1, 2, 3]) // number | undefined
const b = first(["x", "y"]) // string | undefinedfunction byId<T extends { id: string }>(items: T[]): Map<string, T> {
return new Map(items.map((item) => [item.id, item]))
}| Smell | Why |
|---|---|
| T used only once | May not express a relationship |
| Too many type parameters | Hard to infer and explain |
| Manual type args required often | API may be hard to infer |
| Generic returns unrelated T | Likely unsafe or over-abstract |