Conditional Types and Mapped Types
2 min read•Effective TypeScript
Conditional Types and Mapped Types
These features let you compute types based on other types. They are the foundation of TypeScript’s advanced patterns.
Item 80: Use Conditional Types for Type‑Level Logic
TYPESCRIPT
type IsString<T> = T extends string ? true : false;
const a: IsString<"hi"> = true;
const b: IsString<123> = false;Conditional types let you describe type‑level branching.
Item 81: Understand Distributive Conditional Types
Conditional types distribute across unions:
TYPESCRIPT
type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>;
// Result: string[] | number[]This is powerful but can be surprising; use parentheses to prevent distribution:
TYPESCRIPT
type NonDistribute<T> = [T] extends [any] ? T[] : never;
type R = NonDistribute<string | number>; // (string | number)[]Item 82: Use infer to Extract Types
TYPESCRIPT
type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never;
type Args<T> = T extends (...args: infer A) => any ? A : never;Item 83: Use Mapped Types for Object Transforms
TYPESCRIPT
type Optional<T> = { [K in keyof T]?: T[K] };
type ReadonlyUser = Readonly<User>;Mapped types can add or remove modifiers:
TYPESCRIPT
type Mutable<T> = { -readonly [K in keyof T]: T[K] };Item 84: Use Key Remapping for API Shapes
TYPESCRIPT
type Getterify<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};This is great for building fluent APIs.
Item 85: Use Template Literal Types for String Rules
TYPESCRIPT
type Route = `/${string}`;
type EventName = `on${Capitalize<string>}`;These enforce format rules at compile time.
Scenario: Strongly Typed Event Handlers
TYPESCRIPT
type EventMap = {
click: { x: number; y: number };
hover: { elementId: string };
};
type HandlerName = `on${Capitalize<keyof EventMap & string>}`;
type Handlers = {
[K in keyof EventMap as `on${Capitalize<K & string>}`]: (
e: EventMap[K],
) => void;
};
const handlers: Handlers = {
onClick: (e) => console.log(e.x, e.y),
onHover: (e) => console.log(e.elementId),
};Key Takeaways
- Conditional types enable type‑level branching.
- Distribution over unions is powerful but needs care.
inferextracts type information.- Mapped types transform object shapes.
- Template literal types enforce string formats.
Next: built‑in utility types.