Guide to advanced TypeScript types
Key takeaway
In one line: Advanced types are tools to make invalid states unrepresentable. The more you close
anyholes with branded types, generics, and narrowing, the cheaper refactors become.
Introduction
TypeScript already cuts many bugs with static types alone. Adding generics, conditional types, and mapped types lets you shape APIs and shared utilities more safely. Here we focus on patterns we use in large codebases and common pitfalls.
Generics
Generics parameterize types so components stay reusable.
Basic generics
Generic constraints
Generic classes
Union and intersection types
Union types
Intersection types
Conditional types
Conditional types pick one of two types based on a type relation.
Basic conditional types
Distributive conditional types
Practical example: extracting a function’s return type
Mapped types
Mapped types derive new types from existing ones.
Basic mapped type
Partial and Required
Pick and Omit
Template literal types
Template literal types combine string literal types into new string types.
Type guards
Type guards narrow types at runtime.
User-defined type guards
Practical examples
API response typing
Combining utility types
Conclusion
Using advanced TypeScript well gives you:
- Stronger safety: catch errors at compile time
- Reuse: less duplication via generics and utilities
- Readability: types as documentation
- Maintainability: see impact when types change
Used judiciously, these features make codebases safer and easier to evolve.