Programming Languages6 min read

TypeScript Advanced Types

Master TypeScript's type system: conditional types, mapped types, template literal types, infer keyword, and building type-safe utility libraries.

typescripttypesgenericsadvanced

TypeScript's type system is Turing-complete - you can compute types at compile time. Advanced type features (conditional types, mapped types, template literals) enable building APIs that are both flexible and type-safe, catching entire categories of runtime errors at compile time.

Invest in TypeScript's type system when the type complexity pays for itself in safety or DX. Generic constraints and conditional types enable APIs that are specific and safe. Use `satisfies` over `as` for type validation without widening.

Workflow

  1. Use conditional types and inferConditional types extract and transform types programmatically - the foundation of TypeScript utility types.
  2. Write mapped typesMapped types transform every property in a type - enabling utilities like `Partial`, `Required`, `Readonly`.
  3. Use template literal typesTemplate literal types enable string manipulation at the type level - useful for event names, CSS properties, API paths.
  4. Build discriminated unionsDiscriminated unions enable exhaustive type narrowing - TypeScript tells you when you're missing a case.
  5. Apply satisfies and const assertions`satisfies` validates type conformance without widening; `as const` preserves literal types for exact value inference.

Output Format

Conditional types with `infer`, mapped types for type transformation, template literals for string computation, discriminated union with exhaustive `never` check, `satisfies` for validated inference.

Examples

Type-safe event bus: `type EventMap = { "user:login": { userId: string }; "order:created": { orderId: string; total: number } }; type Listener<T extends keyof EventMap> = (data: EventMap[T]) => void; function on<T extends keyof EventMap>(event: T, listener: Listener<T>): void`
Deep partial: `type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T; // useful for update payloads where any subset of fields can be updated`
Validated lookup: `const HTTP_STATUS = { OK: 200, CREATED: 201, BAD_REQUEST: 400, UNAUTHORIZED: 401 } as const satisfies Record<string, number>; type StatusCode = (typeof HTTP_STATUS)[keyof typeof HTTP_STATUS] // 200 | 201 | 400 | 401`

Edge Cases & Gotchas

  • Recursive types: TypeScript supports recursive conditional types with a depth limit. Very deep recursion (1000+ levels) hits the instantiation limit. Use `interface` recursion (which is lazily evaluated) instead of `type` recursion for deeply nested structures
  • Variance: TypeScript uses structural subtyping. Function return types are covariant; parameter types are contravariant. Understanding this explains why `(x: Dog) => void` is not assignable to `(x: Animal) => void`
  • Type-level programming complexity: overly complex type gymnastics hurt maintainability. If a type definition takes more than 10 lines to understand, consider simplifying the API design rather than the types

When to Break These Rules

  • For internal scripts and one-off tools, TypeScript type complexity isn't worth the investment. Use `any` liberally in scripts; reserve advanced types for public APIs and libraries.

Reference Files

  • TypeScript handbook: https://www.typescriptlang.org/docs/handbook/
  • type-challenges: https://github.com/type-challenges/type-challenges
  • Effective TypeScript (book): Dan Vanderkam
  • TypeScript deep dive: https://basarat.gitbook.io/typescript/

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.