1. Introduction
A mapped type builds a new object type by iterating over the properties of an existing type and applying a transformation to each one. Instead of writing type ReadonlyTask = { readonly title: string; readonly done: boolean } by hand, you write a single generic rule once and TypeScript applies it to every key. Mapped types are the mechanism behind built-in utility types such as Partial<T>, Readonly<T>, Pick<T, K>, and Record<K, T>, and they are essential for writing generic, DRY type-level transformations in advanced TypeScript code.
Cricket analogy: A mapped type is like a rule that automatically marks every column of a scorecard (runs, balls, fours) as locked-in once the innings ends, instead of manually retyping a ReadonlyScorecard type for each stat.
2. Syntax
type MappedType<T> = {
[K in keyof T]: T[K]; // identity mapping
};
type ReadonlyMapped<T> = {
readonly [K in keyof T]: T[K]; // add a modifier
};
type OptionalMapped<T> = {
[K in keyof T]?: T[K]; // add optionality
};
type RequiredMapped<T> = {
[K in keyof T]-?: T[K]; // remove optionality (- modifier)
};
// key remapping with `as` (TS 4.1+)
type RenamedMapped<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};3. Explanation
The clause [K in keyof T] iterates K over the union of property names produced by keyof T, and for each K the right-hand side describes the type of the resulting property, typically T[K] (an indexed access type) to preserve the original property's type. Modifiers readonly and ? can be added or, using a - prefix (-readonly, -?), explicitly stripped from the source type — this is how Required<T> is implemented ({ [K in keyof T]-?: T[K] }) as the inverse of Partial<T>.
Cricket analogy: [K in keyof Scorecard] iterating over "runs" | "wickets" is like a scoreboard operator going column by column, keeping each field's original type with Scorecard[K]; stripping the ? with -? is like insisting every optional stat (like "notOutBonus") must now be filled in, mirroring how RequiredScorecard forces completeness.
Since TypeScript 4.1, the as clause inside a mapped type lets you remap keys entirely, producing a different property name than the source, which is how Getters<T> style APIs and Record-based lookup transformations are built. The remapped key expression is itself a template literal type, so it composes with keyof, Capitalize, Uppercase, and conditional types.
Cricket analogy: The as clause remapping "runs" to "getRuns" is like a broadcaster renaming a raw stat column into a commentary label, composing Capitalize<K> with the property name so every Getters<Scorecard> method reads "getRuns" instead of the source field.
Mapped types only iterate over keyof T. If T has an index signature (e.g. { [key: string]: number }), keyof T resolves to string | number, and the mapped result inherits an index signature rather than named properties — this differs from mapping over an object literal type with named keys.
Gotcha: applying as with a key expression that evaluates to never for some K silently drops that property from the mapped type — this is exactly how Omit<T, K> and conditional key filtering work, but it can be an easy source of confusion when a property mysteriously disappears from a derived mapped type. Always check whether your remapping expression can collapse to never.
4. Example
type Task = {
title: string;
done: boolean;
priority: number;
};
type ReadonlyTask = {
readonly [K in keyof Task]: Task[K];
};
type StringifiedTask = {
[K in keyof Task]: string;
};
const t: ReadonlyTask = { title: "Ship v1", done: false, priority: 1 };
console.log(Object.keys(t).join(", "));
const s: StringifiedTask = { title: "Ship v1", done: "false", priority: "1" };
console.log(Object.values(s).join(" | "));
// key remapping with `as`
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type TaskGetters = Getters<Task>;
const getters: TaskGetters = {
getTitle: () => t.title,
getDone: () => t.done,
getPriority: () => t.priority,
};
console.log(getters.getTitle(), getters.getDone(), getters.getPriority());5. Output
title, done, priority
Ship v1 | false | 1
Ship v1 false 16. Key Takeaways
- A mapped type has the form
{ [K in keyof T]: ... }, iterating overT's property names. - The
readonlyand?modifiers can be added or removed (with a-prefix) inside the mapping. - The
asclause (TS 4.1+) lets you remap or filter keys, including dropping keys by mapping them tonever. - Mapped types are the mechanism behind
Partial,Required,Readonly,Pick, andRecord. keyof Tcombined with an index signature yieldsstring | numberrather than named literal keys.
Practice what you learned
1. What does `{ [K in keyof T]-?: T[K] }` do?
2. In a mapped type, what does the `as` clause after `K in keyof T` allow you to do?
3. Gotcha: if a mapped type's `as` key expression evaluates to `never` for a given K, what happens to that property?
4. What does `keyof T` produce when T has an index signature `{ [key: string]: number }` and no named properties?
5. Which utility type below is essentially `{ readonly [K in keyof T]: T[K] }`?
Was this page helpful?
You May Also Like
Conditional Types in TypeScript
Branch at the type level with `T extends U ? X : Y`, including how distributive conditional types behave over union types.
keyof and typeof Operators in TypeScript
Use `keyof T` to get a union of a type's property names, and `typeof x` in a type position to extract the type of a value.
Utility Types in TypeScript
Learn TypeScript's built-in generic utility types — Partial, Required, Readonly, Pick, Omit, and Record — for transforming existing types.
Generic Constraints in TypeScript
Learn how to restrict generic type parameters with `extends` so generic code can safely rely on specific properties or shapes.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics