Introduction to TypeScript Mapped Types

Mapped types in TypeScript provide a way to create new types by transforming existing ones. They are a powerful tool for handling complex type operations and ensuring type safety in TypeScript applications. This article introduces mapped types, explains their syntax, and provides examples to demonstrate their use.

What Are Mapped Types?

Mapped types allow for the creation of new types by applying a transformation to each property of an existing type. They are often used to modify or extend types in a flexible manner. The basic syntax of a mapped type is:

type MappedType = {
  [K in keyof T]: NewType;
};

In this syntax:

  • T is the original type.
  • K represents each key in T.
  • NewType is the new type assigned to each property.

Basic Example of Mapped Types

Here is a simple example of a mapped type that converts all properties of a given type to read-only:

type ReadOnly = {
  readonly [K in keyof T]: T[K];
};

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

type ReadOnlyUser = ReadOnly;

In this example, the ReadOnly mapped type transforms all properties of the User type to be read-only, resulting in a new type ReadOnlyUser where all properties are immutable.

Mapped Types with Type Transformations

Mapped types can also be used to transform types in more complex ways. For instance, a mapped type that makes all properties optional:

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

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

type PartialUser = Partial;

In this example, the Partial mapped type makes all properties of the User type optional, resulting in a new type PartialUser where each property is optional.

Using Mapped Types with Conditional Types

Mapped types can be combined with conditional types for more sophisticated type operations. For example, creating a type that only includes properties of a certain type:

type OnlyStrings = {
  [K in keyof T]: T[K] extends string ? T[K] : never;
};

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

type StringProperties = OnlyStrings;

In this example, the OnlyStrings mapped type filters out properties that are not of type string, resulting in a new type StringProperties that includes only string properties from the User type.

Advanced Mapped Types

Advanced use cases for mapped types include creating types that modify existing types based on various conditions. For example, a mapped type that adds a suffix to each property name:

type WithSuffix<T, S extends string> = {
  [K in keyof T as `${string & K}${S}`]: T[K];
};

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

type UserWithSuffix = WithSuffix<User, "Prop">;

In this example, the WithSuffix mapped type adds a suffix to each property name of the User type, resulting in a new type UserWithSuffix where property names have the specified suffix.

Conclusion

Mapped types in TypeScript are a versatile feature that enables developers to create new types by transforming existing ones. By understanding and utilizing mapped types, developers can manage complex type transformations and ensure greater type safety in their TypeScript code. Mapped types offer powerful capabilities for enhancing and customizing type definitions in TypeScript applications.