Skip to main content

TypeScript Mapped Types

A mapped type builds a new type by walking over every property of an existing type and changing it in the same way.

  • Mapped types = transform every property of a type
  • Common built-in ones: Partial, Readonly, Pick, Omit, Record

A small mapped type example

Starting from a Person type, one mapped type makes every property optional and another makes every property readonly.

script.ts
// Small example
type Person = { name: string; age: number };
type PartialPerson = { [P in keyof Person]?: Person[P] };
type ReadonlyPerson = { readonly [P in keyof Person]: Person[P] };

Basic Mapped Type Syntax

The core syntax of a mapped type is { [P in K]: T }, where:

  • P is the property name currently being visited
  • K is a union of the property names to walk over (often keyof SomeType)
  • T is the type each property gets in the new type

Example

PartialPerson adds ? to every property of Person, so an object with only name is allowed. ReadonlyPerson adds readonly to every property, so assigning to age afterwards would be a compile error.

Prompt
Show the core mapped type syntax { [P in K]: T } by transforming an interface by hand. Declare a Person interface with name: string, age: number and email: string. Build a PartialPerson mapped type that makes every property optional and create a partialPerson object with only name: "John". Then build a ReadonlyPerson mapped type that marks every property readonly, create a full readonlyPerson (Alice, 30, alice@example.com), and leave a commented-out reassignment of age explaining it would be a read-only error. Nothing is printed.
Output: TypeScript file and captured output

Built-in Mapped Types

TypeScript's standard library already includes several useful mapped types, so you do not have to write the common ones yourself:

  • Partial<T>: make all properties optional
  • Readonly<T>: make all properties readonly
  • Pick<T, K>: keep only a chosen set of keys
  • Omit<T, K>: remove a set of keys
  • Record<K, V>: map a set of keys to one value type

Example

Each alias below applies one built-in mapped type to User. The comment after each alias shows the object type it produces. Required is also shown — it is the opposite of Partial.

Prompt
Show the built-in mapped utility types applied to one interface. Declare a User interface with id: number, name: string, email: string and isAdmin: boolean, then create type aliases using Partial<User>, Required<Partial<User>>, Readonly<User>, Pick<User, "email" | "id">, Omit<User, "id" | "isAdmin"> and Record<"admin" | "user" | "guest", string>, each followed by a comment spelling out the equivalent object type. The file only declares types and prints nothing.
Output: TypeScript file and captured output

Creating Custom Mapped Types

You can write your own generic mapped types to transform types in exactly the way you need.

Example

StringifyProperties<T> turns every property into a string. Validator<T> turns every property into a function that receives a value of that property's type (T[P]) and returns a boolean, so productValidator must supply one check per property of Product.

Prompt
Show two custom generic mapped types built on a Product interface (id: number, name: string, price: number, inStock: boolean). Write StringifyProperties<T> that turns every property into string, and Validator<T> that turns every property P into a function (value: T[P]) => boolean. Apply the first to get a StringProduct type and use the second to build a productValidator object whose checks are: id greater than 0, non-empty name, price at least 0, and inStock being a boolean. Nothing is printed.
Output: TypeScript file and captured output

Modifying Property Modifiers

A mapped type can also add or remove the property modifiers readonly and ? (optional). Writing +readonly or readonly adds the modifier; writing -readonly removes it. The same works for ? with -?.

Example

Mutable<T> uses -readonly to strip the read-only flag from every property of Configuration. RequiredProps<T> uses -? to make every optional property required.

Prompt
Show how a mapped type can remove the readonly and ? modifiers with -readonly and -?. Declare a Configuration interface with readonly apiKey: string, readonly apiUrl: string, timeout?: number and retries?: number. Write Mutable<T> (strips readonly from every property) and RequiredProps<T> (strips ? from every property), apply each to Configuration as MutableConfig and RequiredConfig, and comment the equivalent object type after each. The file only declares types and prints nothing.
Output: TypeScript file and captured output

Advanced Mapped Types

Mapped types become even more powerful when you combine them with conditional types. The new type of each property can then depend on the old one.

Example

FormattedResponse<T> checks each property with T[P] extends number and converts numeric properties to string. StringPropsOnly<T> uses an as clause to rename keys: properties that are not strings are mapped to never, which drops them from the result.

Prompt
Combine mapped types with conditional types on an ApiResponse interface (data: unknown, status: number, message: string, timestamp: number). Write FormattedResponse<T> that maps every number property to string and leaves the others unchanged, and StringPropsOnly<T> that uses an as key-remapping clause to keep only the properties whose type is string. Apply both to ApiResponse and comment the resulting types. Nothing is printed.
Output: TypeScript file and captured output

Key Takeaways

Mapped types let you transform every property of a type in a consistent way.

Key concepts:

  • Type transformation: change property types in bulk
  • Property modifiers: add or remove readonly and ?
  • Key remapping: rename or filter properties with an as clause
  • Composition: combine mapped types with other TypeScript features such as conditional types

Common use cases:

  • Creating read-only versions of types
  • Making all properties optional or required
  • Transforming property types (for example to nullable or readonly)
  • Filtering properties based on their types
  • Creating type-safe utility functions