Mapped Types Intro
Transform every property of a type with {[K in keyof T]: …} — the engine behind Partial, Readonly, Pick patterns, and typed form bags.
- typescript
- mapped-types
A mapped type builds a new object type by iterating keys:
type OptionsFlags<T> = {
[K in keyof T]: boolean;
};
type FeatureFlags = OptionsFlags<{ darkMode: () => void; newUser: () => void }>;
// { darkMode: boolean; newUser: boolean }
If you’ve used Partial, Required, Readonly, or Record, you’ve used mapped types.
Docs: Mapped Types, keyof.
Core syntax
type Mapper<T> = {
[K in keyof T]: T[K]; // identity map
};
K in …— key iterationT[K]— original value type via indexed access- Modifiers:
readonly,?, and prefixes-readonly,-?
Reimplementing Partial and Readonly
type MyPartial<T> = {
[K in keyof T]?: T[K];
};
type MyReadonly<T> = {
readonly [K in keyof T]: T[K];
};
type MyRequired<T> = {
[K in keyof T]-?: T[K];
};
-? removes optionality. -readonly removes readonly.
Key remapping (as)
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type UserGetters = Getters<{ name: string; age: number }>;
// { getName: () => string; getAge: () => number }
Filter keys by remapping to never:
type OnlyStrings<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K];
};
Record
type Record<K extends keyof any, T> = {
[P in K]: T;
};
type RolePermissions = Record<'admin' | 'user' | 'guest', string[]>;
Prefer Record<Union, V> over index signatures when the key set is closed.
Forms and dirty fields
type FormValues = {
email: string;
password: string;
remember: boolean;
};
type DirtyFlags = { [K in keyof FormValues]: boolean };
type FieldErrors = { [K in keyof FormValues]?: string };
Or partial records: Record and Partial patterns for forms.
Homomorphic mapped types
When you write { [K in keyof T]: … }, TypeScript preserves optional/readonly modifiers from T in many cases (homomorphic mapping). That keeps Partial-like behavior well-behaved on optional fields.
Combining with conditionals
type NonFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends (...args: never[]) => unknown ? never : K;
}[keyof T];
type NonFunctionProps<T> = Pick<T, NonFunctionPropertyNames<T>>;
This pattern powers “props without methods” helpers.
Template + map for event maps
type Events = {
click: MouseEvent;
keydown: KeyboardEvent;
};
type Handlers = {
[K in keyof Events as `on${Capitalize<string & K>}`]?: (e: Events[K]) => void;
};
// { onClick?: (e: MouseEvent) => void; onKeydown?: … }
Footguns
- Mapping
stringkeys — produces huge/weak types; prefer key unions. - Forgetting
string & K— needed whenKisstring | number | symbolin template remaps. - Excessive nesting — intermediate aliases for readability.
- Runtime — mapped types erase; build runtime keys with
Object.keys+ validation separately.
Interview out-loud answer
“Mapped types iterate keys with in keyof to transform property types — that’s how Partial and Readonly work. I use them for form error maps, flag maps, and key remapping with as. They stay in the type system only; runtime still needs real objects.”
Related on this site
- Utility types Partial Pick Omit
- keyof typeof and indexed access
- Conditional types intro
- Template literal types
- Record and Partial patterns for forms
Further reading
Related guides
- Basic Types and AnnotationsPrimitives, arrays, objects, and function annotations TypeScript actually checks — plus where inference is enough and where it is not.
- Branded Types for IDsNominal-style UserId vs OrderId in TypeScript — prevent ID mixups at compile time with brands, parsers, and form boundaries.
- Conditional Types IntroT extends U ? X : Y — how TypeScript picks types from conditions, distributes over unions, and powers utility types you already use.
- Declaration Files and DefinitelyTypedHow .d.ts files describe JS to TypeScript, when to use @types packages, module augmentation, and writing minimal ambient types for untyped libs.
- Discriminated Unions for UI StateModel loading, success, and error as mutually exclusive variants so TypeScript and your UI cannot show impossible states.