Advanced Type Features
Mapped types, template literals, utility types, and inference for sophisticated type-level programming.
Mapped Types
Mapped types transform properties of an existing type: `type ReadonlyUser = { readonly [K in keyof User]: User[K] }`. The `in keyof T` loop iterates property names at the type level.
Built-in utilities `Partial`, `Required`, `Readonly`, and `Record` are implemented as mapped types. Use them before writing custom versions — they are battle-tested and familiar to contributors.
- `[K in keyof T]` transforms properties
- Built-in utilities use mapped types
- Prefer utilities over custom reimplementation
type PartialUser = Partial<User>; type UserFlags = Record<keyof User, boolean>;
Template Literal Types
Template literal types build string types from fragments: `type EventName = `on${Capitalize<Kind>}``. They power typed CSS variables, route paths, and event name generation in design systems.
Combine with union distribution: when a union is used in a template, TypeScript distributes over each member. This enables exhaustive string pattern generation from const unions.
- String types from template patterns
- Distribution over unions
- Typed routes and event names
type Route = `/users/${string}` | '/users';
type Getter = `get${Capitalize<string>}`;Utility Types in Practice
`Pick<T, K>` and `Omit<T, K>` select or exclude properties. `Extract<T, U>` and `Exclude<T, U>` filter union members. `NonNullable<T>` removes null and undefined. `ReturnType<T>` and `Parameters<T>` extract function signature parts.
`Awaited<T>` unwraps Promise types — essential for typing async function returns. Compose utilities rather than duplicating large type definitions manually.
- Pick/Omit for property selection
- ReturnType/Parameters for functions
- Awaited for Promise unwrapping
type UserPreview = Pick<User, 'id' | 'name'>; type CreateUserParams = Parameters<typeof createUser>[0];
Type Inference with typeof and infer
`typeof value` in type position extracts the type of a value — useful for deriving types from const config objects and zod schemas. `infer` inside conditional types extracts nested types, powering library magic like React component prop inference.
`satisfies` operator (TS 4.9+) validates that a value matches a type while preserving the narrower inferred literal type — ideal for config objects and design tokens.
- `typeof` for value-to-type extraction
- `satisfies` preserves literal inference
- `infer` for nested type extraction
const routes = {
home: '/',
profile: '/profile',
} as const satisfies Record<string, string>;When to Stop Abstracting
Advanced types improve library DX but can obscure application code. If a type requires a paragraph to explain, consider simplifying the runtime API instead.
Reach for advanced types when the same pattern repeats across dozens of callsites — form field paths, API route typing, or action dispatch maps. Otherwise, explicit interfaces remain clearer for most team members.
- Complex types obscure application code
- Use for repeated cross-cutting patterns
- Prefer simple interfaces when sufficient