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.
Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.