Advanced TypeScript Types for Better Code
TypeScript's type system goes far beyond basic interfaces and enums. Advanced types catch more bugs, reduce boilerplate, and document code more precisely.
Generics
Generics parameterize types. A generic function works with any type while maintaining type safety. Type parameters infer from usage—explicit annotation is often unnecessary. Constrain type parameters with extends to limit acceptable types.
Generic constraints with keyof access the keys of an object type. T[K] (indexed access) retrieves the type of property K in type T. This enables type-safe property access and transformation functions.
Conditional Types
Conditional types select types based on conditions: T extends U ? X : Y. They are TypeScript's equivalent of ternary expressions at the type level. Nested conditionals handle multiple branches.
The infer keyword extracts types from within other types. ReturnType
Mapped Types
Mapped types transform object types by mapping over keys: { [K in keyof T]: NewType }. Readonly
Key remapping with as creates mapped types that rename keys. Filter keys with as and a conditional type. These patterns implement advanced utilities like Omit, Extract, and Exclude.
Template Literal Types
Template literal types construct string types at the type level: `${prefix}${suffix}`. They combine with union types to generate all possible string patterns. Use with infer to parse URL patterns, routes, and string-based protocols.
Practical Usage
Use branded types for type-safe IDs (type UserId = string & {__brand: 'UserId'}). Use discriminated unions with switch-case exhaustiveness checking. Use satisfies keyword for type validation without widening.
Utility Types
Learn built-in utility types: Partial, Required, Readonly, Record, Pick, Omit, Exclude, Extract, NonNullable, ReturnType, InstanceType, Parameters, Awaited. Combine them for complex type transformations without custom type definitions.