Glossary / Generics

Generics

Generics let TypeScript describe relationships among types while writing reusable functions, classes, interfaces, and aliases. A type parameter captures a relationship that would otherwise be lost by using any or a broad union, and constraints limit which types are valid inputs.

Inference and constraints

function first<T>(items: readonly T[]): T | undefined {
  return items[0];
}
const value = first([1, 2, 3]); // number | undefined

The compiler often infers type arguments from function arguments and context. A constraint such as T extends { id: string } allows safe use of id while preserving the caller's more specific subtype. Defaults can provide fallback type arguments. Generic parameters should represent a real input/output relationship; unused parameters add complexity without safety.

Generics are erased at runtime. T cannot be inspected with typeof, used as a constructor, or validate parsed data unless a runtime value (schema, constructor, predicate) is separately passed. Constraints are compile-time guarantees about callers, not runtime checks.

Variance and design pitfalls

Variance describes how subtype relationships between type arguments affect assignability. Function positions, mutable containers, callbacks, and compiler settings influence variance behavior. Mutable generic structures can be unsafe when treated covariantly; readonly interfaces often model producer-only use more accurately. Inference can widen literals; const type parameters and as const preserve detail in selected cases.

Avoid complex generic APIs whose inferred types are unreadable. Prefer explicit type parameters only when inference fails or clarity improves. Test public generic declarations with representative calls and negative cases.

Interview questions

  1. Why use T rather than any? It preserves a relationship between inputs and outputs and enables checking.
  2. What does T extends X do? Constrains valid T types and exposes X's members safely.
  3. Can generics validate JSON at runtime? No; type parameters erase, so runtime validation needs a value-level schema/check.
  4. What is variance? How subtyping between type arguments affects assignability of the constructed types.
  5. When use readonly generic inputs? When the function only reads data, avoiding unnecessary mutable variance constraints.

References