Different ways to Create a TypeScript Mapped Type Utility Type
Last Updated :
07 Feb, 2024
Mapped types in TypeScript are a powerful and flexible feature that allows developers to create new types by transforming existing ones. These types enable you to iterate through the keys of an object type and construct a new type based on the original type’s keys and values. This feature is particularly useful for creating utility types that can modify properties of an existing type in a DRY (Don’t Repeat Yourself) manner, enhancing code maintainability and type safety. Mapped types in TypeScript can be created using various techniques, each serving different purposes and use cases which are as follow:
Basic Mapped Type
A basic mapped type allows you to iterate over the keys of an existing type and apply a transformation to its properties.
Syntax:
type MappedType<T> = {
[P in keyof T]: T[P];
};
Example: Creating a simple mapped type that mirrors the original type. This example demonstrates a basic mapped type that creates a new type identical to the original Person type.
Javascript
type Person = {
name: string;
age: number;
};
type ReadOnlyPerson = {
readonly [P in keyof Person]: Person[P];
};
function attemptToUpdatePerson(person: ReadOnlyPerson) {
console.log(
`Before update: Name - ${person.name},
Age - ${person.age}`);
console.log(
`After attempted update: Name - ${person.name},
Age - ${person.age}`);
}
const person: ReadOnlyPerson = {
name: "Bob" ,
age: 30
};
attemptToUpdatePerson(person);
|
Output:
"Before update: Name - Bob, Age - 30"
"After attempted update: Name - Bob, Age - 30"
Making Properties Optional
Mapped types can be used to make all properties of a type optional, useful for creating types that allow partial object updates.
Syntax:
type PartialType<T> = {
[P in keyof T]?: T[P];
};
Example: Transforming a type to make all its properties optional. In this example, PartialType is a mapped type that makes every property of Person optional, demonstrating the utility of mapped types in modifying property optionality.
Javascript
type Person = {
name: string;
age: number;
};
type PartialPerson = {
[P in keyof Person]?: Person[P];
};
function logPersonInfo(person: PartialPerson) {
console.log(`Name: ${person.name}`);
if (person.age !== undefined) {
console.log(`Age: ${person.age}`);
} else {
console.log(`Age is not provided.`);
}
}
const partialPerson: PartialPerson = {
name: "Alice"
};
logPersonInfo(partialPerson);
|
Output
"Name: Alice"
"Age is not provided."
Creating Read-Only Types
Mapped types can also enforce immutability by making all properties of a type read-only.
Syntax:
type ReadOnlyType<T> = {
readonly [P in keyof T]: T[P];
};
Example: Creating a read-only version of a type. This example illustrates how to create an immutable version of the Person type using mapped types, showcasing their ability to enforce property immutability.
Javascript
type Person = {
name: string,
age: number,
};
type ReadOnlyPerson = Readonly<Person>;
function displayPersonInfo(person: ReadOnlyPerson) {
console.log(`Name: ${person.name}, Age: ${person.age}`);
}
function attemptToModifyPerson(person: ReadOnlyPerson) {
console.log(
`Attempting to modify a read-only person object...`);
displayPersonInfo(person);
}
const person: ReadOnlyPerson = {
name: "Bob" ,
age: 30,
};
displayPersonInfo(person);
attemptToModifyPerson(person);
|
Output
"Name: Bob, Age: 30"
"Attempting to modify a read-only person object..."
"Name: Bob, Age: 30"
Mapped types can also transform the types of the properties of an existing type, allowing for comprehensive type manipulation.
Syntax:
type PropertyTypeTransform<T> = {
[P in keyof T]: T[P] extends infer R ? Transform<R> : never;
};
Example: Converting all string properties of a type to boolean flags. Here, StringToBoolean is a mapped type that transforms all string properties of the Person type into booleans.
Javascript
type User = {
id: number;
name: string;
email: string;
verified: boolean;
};
type StringsToBooleans<T> = {
[P in keyof T]: T[P] extends string ? boolean : T[P];
};
function transformStringsToBooleans<T>(user: T):
StringsToBooleans<T> {
let result = {} as StringsToBooleans<T>;
for (const key in user) {
if ( typeof user[key] === 'string' ) {
result[key] = true ;
} else {
result[key] = user[key];
}
}
return result;
}
const user: User = {
id: 1,
name: "Alice" ,
email: "alice@example.com" ,
verified: false ,
};
const transformedUser =
transformStringsToBooleans(user);
console.log(transformedUser);
|
Output
"Name: Bob, Age: 30"
"Attempting to modify a read-only person object..."
"Name: Bob, Age: 30"
Share your thoughts in the comments
Please Login to comment...