Mapped types iterate over the keys of an existing type and produce a new type with transformed properties. They are the mechanism behind Partial, Required, Readonly, and Pick -- and once you understand how they work, you can build your own utility types that fit your codebase exactly. If you have ever written a type by hand that mirrors another type with slight modifications, a mapped type would have done it in three lines.
Master typescript mapped types
Take the TypeScript Type System Mastery course with hands-on lessons and challenges.
Partial alone makes properties optional, but does not allow null. In real APIs, PATCH operations often need to distinguish between "field not sent" (undefined) and "field explicitly cleared" (null). This mapped type handles both.
Readonly is itself a mapped type that adds the readonly modifier to every property. The -readonly modifier strips it back off. This pattern keeps your insert types lean and derives the read types automatically.
The mapped type guarantees exhaustive coverage. If someone adds a new field to RegistrationForm, TypeScript immediately flags the missing validator. The parameter type is inferred from the field, so you cannot accidentally validate a string as a number.
The as clause with a conditional that returns never filters out non-function keys entirely. This is cleaner than Pick with a complex key extraction type, and it stays in sync automatically when the source interface changes.
This combines three features in one mapped type: key remapping with template literals to rename methods, conditional types with infer to extract parameter and return types, and Promise wrapping to convert synchronous signatures to async. You see this pattern when adapting local APIs into remote service interfaces.
Record<K, V> is just syntactic sugar for { [P in K]: V }. Writing the mapped type yourself becomes useful when you want different value types per key, or when you combine it with conditional types to vary the shape based on the key.
Writing `[K in T]` instead of `[K in keyof T]` -- forgetting that you need `keyof` to extract the keys from an object type
Always use `keyof` to get the property names: `[K in keyof T]: T[K]`. Without `keyof`, TypeScript expects `T` itself to be a union of strings/numbers/symbols, which is only valid when you are intentionally mapping over a custom union like `[K in "a" | "b"]`.
Using `Capitalize<K>` directly in a key remapping when `K` could be a symbol -- this causes a type error because Capitalize only accepts strings
Intersect with `string` first: `Capitalize<string & K>`. Since `keyof T` can include symbols and numbers, the intersection narrows K to only string keys. This is required in every mapped type that uses template literal transformations on keys.
Expecting that adding `| undefined` to a property value is the same as making it optional with `?` -- e.g., writing `{ [K in keyof T]: T[K] | undefined }` when you wanted `Partial`
Adding `| undefined` makes the value nullable but the key is still required. Use `[K in keyof T]?: T[K]` with the `?` modifier to actually make properties optional. With `exactOptionalPropertyTypes` enabled, the difference is even more visible.
Building overly complex single mapped types that combine filtering, remapping, and conditional value transformation -- making the type unreadable and hard to debug
Compose smaller utility types instead. Write a `MethodsOf<T>` that filters, then a `Prefixed<T>` that renames, then combine them: `Prefixed<MethodsOf<Service>>`. Each type is testable and understandable on its own.
Mapped types transform existing types by iterating over their keys with `[K in keyof T]` syntax. Modifier operators (`+?`, `-?`, `+readonly`, `-readonly`) control optionality and immutability. Key remapping with `as` (TS 4.1+) enables renaming keys via template literals and filtering keys by returning `never`. In practice, you will use mapped types to build patch DTOs, derive form validators from schemas, extract method-only interfaces, and convert between sync and async API signatures. The built-in utility types are all mapped types -- understanding the pattern lets you build exactly what your codebase needs.
Interactive lessons and challenges on Stanza, practice in VS Code, Cursor, or the web.
Interactive lessons and challenges, right in your code editor.
Check the free courses. No credit card.