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.

Quick Answer: What is a Mapped Type in TypeScript?

A mapped type in TypeScript is a generic type that creates a new type by iterating over the properties (keys) of an existing type. It allows you to transform each property in the original type, for example, by making it readonly or optional. This is a powerful feature for creating reusable utility types.

Syntax:

type NewType = {
  [Property in keyof OriginalType]: TransformedType;
};

Example: Creating a Readonly version of a type

// Original type
interface User {
  name: string;
  age: number;
}

// Mapped type that makes all properties of User readonly
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.

This is different from the Map data structure. A mapped type is a feature for transforming types, whereas Map is a data structure for storing key-value data.

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.

Looking to dive deeper into TypeScript map types and other essential TypeScript concepts? Check out our TypeScript course.

Key Takeaways for TypeScript Mapped Types

  • Creates New Types from Existing Types: The main purpose of a mapped type is to take an existing type and create a new one by transforming its properties.
  • Core Syntax is [K in keyof T]: This syntax iterates over every key (K) in a given type (T), allowing you to define a new type for each property.
  • Add or Remove Modifiers: You can easily add modifiers like readonly or ? (optional), or remove them with readonly and ?.
  • Enables Reusable Utility Types: This pattern is the foundation for many of TypeScript's most useful built-in utility types, like Partial<T>, Readonly<T>, and Required<T>.
  • Different from the Map Data Structure: Do not confuse mapped types, which are a type-level feature for defining shapes, with the Map object, which is a runtime data structure for storing key-value pairs.
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

Reach your coding goals faster