What is a Mapped Type in TypeScript?
Learn what mapped types are in TypeScript, how Partial and Readonly work internally, modifier syntax, and key remapping with as, with clear code examples.
Expected Interview Answer
A mapped type builds a new type by iterating over the keys of an existing type and transforming each property, using the syntax `{ [K in keyof T]: ... }`, which is how utility types like `Partial<T>`, `Readonly<T>`, and `Pick<T, K>` are implemented under the hood.
`type Optional<T> = { [K in keyof T]?: T[K] }` walks every key `K` of `T` and produces the same key with the same value type, but marked optional. Modifiers can be added or removed explicitly: `-readonly` strips `readonly`, `+?` (or bare `?`) adds optionality, and `-?` removes it. Key remapping via `as` (introduced in TypeScript 4.1) lets you rename or filter keys during the mapping, e.g. `{ [K in keyof T as `get${string & K}`]: () => T[K] }` to generate getter names. Mapped types are purely a compile-time transformation; the resulting type is fully resolved and erased like any other type, with zero runtime cost.
- Powers built-in utility types (`Partial`, `Required`, `Readonly`, `Pick`)
- Avoids manually retyping every property when deriving a related shape
- Key remapping with `as` can rename or filter properties during mapping
- Modifier syntax (`+`/`-` on `readonly`/`?`) gives precise control per property
- Stays in sync automatically when the source type `T` changes
AI Mentor Explanation
A mapped type is like a scoring clerk who takes the batting lineup and produces a new sheet marking every player as 'did not bat yet' by walking down the original list name by name. Instead of typing a fresh sheet from scratch, the clerk mechanically transforms each entry, exactly the way `{ [K in keyof T]: ... }` walks every key of an existing type to build a new one.
Step-by-Step Explanation
Step 1
Iterate with keyof
`{ [K in keyof T]: T[K] }` walks every key `K` of `T`, producing an identical shape as a starting point.
Step 2
Transform the value
Change `T[K]` to something else, e.g. `Promise<T[K]>`, to wrap every property's type.
Step 3
Add or remove modifiers
Use `?` to add optionality, `-?` to strip it, `readonly` to add immutability, and `-readonly` to remove it.
Step 4
Remap keys with as
`{ [K in keyof T as NewKeyExpr]: ... }` (TS 4.1+) can rename keys or filter some out entirely by mapping to `never`.
Step 5
Erase at compile time
The mapped type resolves to a concrete object type during compilation and has no runtime representation, like all TypeScript types.
What Interviewer Expects
- Can write a basic mapped type using `[K in keyof T]`
- Names at least one built-in utility type implemented via mapping (Partial, Readonly, Pick)
- Knows the `+`/`-` modifier syntax for `readonly` and `?`
- Understands key remapping with `as` (TypeScript 4.1+)
- Confirms mapped types are compile-time only with zero runtime cost
Common Mistakes
- Confusing a mapped type with a mapped array (`.map()` at runtime)
- Forgetting `-readonly`/`-?` syntax exists to remove rather than only add modifiers
- Not realizing `Partial<T>`/`Readonly<T>` are themselves just mapped types
- Attempting to use key remapping (`as`) on TypeScript versions before 4.1
Best Answer (HR Friendly)
“A mapped type is a way to automatically generate a new type by transforming every property of an existing type, instead of retyping each field by hand. It's the mechanism behind common built-in helpers like making all fields optional or read-only.”
Code Example
type Optional<T> = { [K in keyof T]?: T[K] };
type Immutable<T> = { readonly [K in keyof T]: T[K] };
type Required2<T> = { [K in keyof T]-?: T[K] };
interface User { id: number; name?: string }
type ReqUser = Required2<User>; // { id: number; name: string }type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
interface Point { x: number; y: number }
type PointGetters = Getters<Point>;
// { getX: () => number; getY: () => number }Follow-up Questions
- How is `Partial<T>` implemented as a mapped type internally?
- What does the `-readonly` modifier do and when would you use it?
- How does key remapping with `as` let you filter out properties entirely?
- How do mapped types interact with conditional types for more complex transforms?
- What is the difference between a mapped type and a plain interface with similar fields?
MCQ Practice
1. What does `{ [K in keyof T]?: T[K] }` produce?
This mapped type iterates every key of T and marks each property optional with `?`, which is exactly how `Partial<T>` is implemented.
2. Which modifier syntax removes the `readonly` modifier in a mapped type?
Prefixing `readonly` with a minus sign (`-readonly`) strips that modifier from each mapped property.
3. What TypeScript feature lets a mapped type rename keys during mapping?
Introduced in TypeScript 4.1, the `as` clause inside `[K in keyof T as ...]` allows renaming or filtering keys during the mapping.
Flash Cards
What is the basic syntax for a mapped type? — `{ [K in keyof T]: SomeTransform<T[K]> }` — iterates every key of T.
How do you remove optionality in a mapped type? — Use the `-?` modifier, e.g. `{ [K in keyof T]-?: T[K] }`.
Name a built-in utility type implemented as a mapped type. — `Partial<T>`, `Readonly<T>`, and `Pick<T, K>` are all mapped types.
What TypeScript version added key remapping with `as`? — TypeScript 4.1.