TYPESCRIPT

TypeScript Map Type: Syntax, Usage, and Examples

TypeScript map types let you transform the properties of an existing type into a new type. You can modify properties by changing their types, making them optional, readonly, or even renaming them dynamically. This feature is useful when you need to create flexible, reusable types without rewriting the same structure multiple times.

How to Use Map Types in TypeScript

You define a map type using the keyof operator to iterate over an existing type’s keys and apply transformations. Here’s the basic syntax:

type Mapped<T> = {
  [K in keyof T]: T[K];
};

This mapped type takes every key K from T and keeps the same type for each key. You can modify this structure to change property behavior.

Example: Making Properties Readonly

You can use mapped types to make object properties readonly:

type User = {
  name: string;
  age: number;
};

type ReadonlyUser = {
  readonly [K in keyof User]: User[K];
};

const user: ReadonlyUser = {
  name: "Alice",
  age: 30
};

user.name = "Bob"; // Error: Cannot assign to 'name' because it is a read-only property

In this example, ReadonlyUser ensures that name and age cannot be modified after assignment.

Using Generic Mapped Types

By adding generics, you make your mapped types more flexible:

type MakeOptional<T> = {
  [K in keyof T]?: T[K];
};

type OptionalUser = MakeOptional<User>;

const user2: OptionalUser = {
  name: "Alice"
}; // 'age' is now optional

This generic mapped type lets you make all properties optional dynamically.

When to Use Map Types in TypeScript

You should use map types when you need to modify an object’s structure without duplicating code. They help when creating utility types for transformations like making properties optional, readonly, or converting types. You can also use them for API response handling, data validation, and object transformations.

Map types ensure that your modifications remain type-safe. If you want to map one type to another while preserving property names, map types provide a structured way to enforce these rules.

Examples of Map Types in TypeScript

Making All Properties Optional

You can make every property in a type optional:

type Partial<T> = {
  [K in keyof T]?: T[K];
};

type UserPartial = Partial<User>;

const user3: UserPartial = {
  name: "John"
}; // 'age' is optional

This is helpful when handling objects that don’t always require every property.

Making All Properties Required

Conversely, you can enforce that all properties must be present:

type Required<T> = {
  [K in keyof T]-?: T[K];
};

type UserRequired = Required<User>;

const user4: UserRequired = {
  name: "Eve",
  age: 25
}; // Error if any property is missing

By using -?, you remove the optional modifier from all properties.

Changing All Property Types

You can convert every property in an object to a specific type:

type ConvertToStrings<T> = {
  [K in keyof T]: string;
};

type UserStrings = ConvertToStrings<User>;

const user5: UserStrings = {
  name: "Alice",
  age: "30"
};

This transformation ensures that all values in UserStrings are now string instead of their original types.

Mapping an Array to an Object Type

Map types also work with arrays when converting their structure:

type ArrayToObject<T> = {
  [K in keyof T]: T[K];
};

type UserArray = ArrayToObject<User[]>;

const users: UserArray = [
  { name: "Alice", age: 30 },
  { name: "Bob", age: 25 }
];

This keeps the user array properly typed.

Learn More About TypeScript Map Types

Mapping a Union Type

You can map union types to different values dynamically:

type Status = "success" | "error" | "loading";

type StatusMessages = {
  [K in Status]: string;
};

const messages: StatusMessages = {
  success: "Operation completed",
  error: "An error occurred",
  loading: "Processing..."
};

Now, every possible status has a corresponding message.

Using Conditional Types with Mapped Types

You can combine mapped types with conditional types for more precise transformations:

type Conditional<T> = {
  [K in keyof T]: T[K] extends string ? boolean : number;
};

type UserConditional = Conditional<User>;

const user6: UserConditional = {
  name: true, // Converted from string to boolean
  age: 30 // Remains a number
};

This structure automatically changes string properties to boolean, leaving number properties unchanged.

Extending and Declaring Map Types

If you need to extend an existing type while renaming properties, you can use mapped types dynamically:

type BaseUser = {
  id: number;
  name: string;
};

type ExtendedUser = BaseUser & {
  [K in keyof BaseUser as `meta_${K}`]: string;
};

const user7: ExtendedUser = {
  id: 1,
  name: "Alice",
  meta_id: "user-1",
  meta_name: "meta-Alice"
};

This type creates new properties prefixed with meta_ while keeping the original ones.

TypeScript map types give you the power to transform object structures dynamically. You can make properties optional, enforce readonly constraints, change types, and create reusable type utilities.

Learn TypeScript for Free
Start learning now
button icon
To advance beyond this tutorial and learn TypeScript by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH