Mapped Types
Mapped Types
Level 9 — Advanced Types A feature that allows you to create a new Object Type by iterating (mapping) over the keys of an existing Object Type, applying transformations along the way. This is the engine that powers Utility Types.
1. Prerequisites
keyofOperator — The iterator used to pull the keys.- Index Signatures — The base syntax of a Mapped Type.
- Utility Types Overview — The output of Mapped Types.
2. Term Category
TypeScript Advanced Type (Iterative Object Transformation Types): Mapped types ({[K in keyof T]: ...}) iterate over property keys to transform existing object types into new structures.
3. Explanation
Environment Context
- Compile-Time
4. Common Mistakes & Pitfalls
Mistake 1: Trying to Map over an Array
The mistake: A developer writes a mapped type and passes an array literal into it: type X = MyMappedType<["name", "age"]>.
Why it's wrong: Mapped Types use in keyof T. keyof expects an Object Type or a Union of string literals. An Array is an object whose keys are 0, 1, 2, 3, so the mapped type will iterate over the array indices, not the string values inside the array!
Golden Rule: Mapped Types iterate over a Union of Literal Strings ("name" | "age"), almost always generated by the keyof operator.
Mistake 2: Attempting Mapped Types inside Interface Declarations
The mistake: Writing interface Bad { [K in keyof T]: string } (TS7028).
Why it's wrong: Mapped type syntax [K in Keys] is permitted ONLY inside type alias declarations, NOT inside interface bodies.
Incorrect:
// interface Bad { [K in keyof User]: string } // ❌ An interface cannot declare a mapped type
Fix:
type Good<T> = { [K in keyof T]: string }; // Correct type alias mapped type
Mistake 3: Forgetting Mapping Modifiers + and - when Adding/Removing Readonly or Optional Modifiers
The mistake: Writing { [K in keyof T]?: T[K] } expecting to remove optionality.
Why it's wrong: To REMOVE optionality ? or readonly, use prefix - (e.g. -? or -readonly). Adding ? adds optionality.
Incorrect:
type MakeRequired<T> = { [K in keyof T]?: T[K] }; // ❌ Adds optionality instead of removing it!
Fix:
type MakeRequired<T> = { [K in keyof T]-?: T[K] }; // Correct: Strips '?' optionality
5. Practice Exercises
Exercise 1: Creating Custom ReadonlyMap<T> Mapped Types
Scenario:
Re-implement the built-in Readonly<T> utility type using a mapped type syntax {[K in keyof T]: T[K]}.
Requirements:
- Define
type MyReadonly<T> = { readonly [K in keyof T]: T[K] }.
Answer
Implementation
type MyReadonly<T> = {
readonly [K in keyof T]: T[K];
};
interface User {
name: string;
age: number;
}
type ReadonlyUser = MyReadonly<User>;
// Inferred as: { readonly name: string; readonly age: number; }
Technical Explanation
- Mapped types
{[K in keyof T]: ...}iterate over every key in typeT. - Adding
readonlybefore the brackets applies thereadonlymodifier to all mapped properties. - Fundamental syntax for building custom object transformation utilities.
Exercise 2: Stripping Readonly and Optional Modifiers
Scenario:
Create a utility type Mutable<T> that strips readonly modifiers using -readonly.
Requirements:
- Define
type Mutable<T> = { -readonly [K in keyof T]: T[K] }.
Answer
Implementation
type Mutable<T> = {
-readonly [K in keyof T]: T[K];
};
interface FrozenState {
readonly id: string;
readonly active: boolean;
}
type WritableState = Mutable<FrozenState>;
// Inferred as: { id: string; active: boolean; }
Technical Explanation
- Prefixing modifiers with
-(e.g.-readonlyor-?) removes those modifiers from mapped properties. Mutable<T>strips immutability constraints from all fields.- Essential technique for type transformation pipelines.
Exercise 3: Mapping Properties to Nullable Unions
Scenario:
Create a mapped type NullableProperties<T> that wraps every property value in a T[K] | null union.
Requirements:
- Define
type NullableProperties<T> = { [K in keyof T]: T[K] | null }.
Answer
Implementation
type NullableProperties<T> = {
[K in keyof T]: T[K] | null;
};
interface Profile {
username: string;
age: number;
}
type NullableProfile = NullableProperties<Profile>;
// Inferred as: { username: string | null; age: number | null; }
Technical Explanation
- Mapped types can transform the value type
T[K]associated with each keyK. T[K] | nullconverts all fields into nullable options.- Standard pattern for draft form state management.
6. Related Terms
Partial<T>&Required<T>— Utility types powered entirely by Mapped Types.Record<Keys, Type>— A utility type built on a Mapped Type.- Key Remapping in Mapped Types (
as) — Related concept: Key Remapping in Mapped Types (as). keyofOperator — Related concept:keyofOperator.- Template Literal Types — Related concept: Template Literal Types.
- Indexed Access Types — Indexed access types.
- Conditional Types — Related concept: Conditional Types.
7. Key Takeaways
- Mapped Types are a way to loop over the keys of an existing type to mathematically generate a brand new type.
- Syntax:
[Key in keyof Type]: NewValueType. - You can add or remove
?(optional) andreadonlymodifiers during the mapping process using+and-. - Mapped Types are the underlying engine that powers almost all built-in Utility Types (like
Partial,Required,Readonly,Pick, andOmit).