TypeScript Mapped Types Explained with Practical Use Cases

Learn what TypeScript mapped types are and how to use them effectively with practical examples. Perfect for beginners looking to understand advanced type manipulation in TypeScript.

If you're learning TypeScript, you might have come across the term "mapped types" and wondered what they are and how you can use them in your projects. Mapped types are a powerful feature that allow you to create new types by transforming the properties of existing ones. This beginner-friendly tutorial will help you grasp mapped types clearly and show you real coding examples to apply them effectively. Understanding mapped types goes hand in hand with knowing about other TypeScript concepts like utility types, generics, and keyof operator.

So, what exactly are mapped types? Simply put, a mapped type takes an existing type and creates a new type by iterating over each property in the original type, applying some transformation or modification to each property’s type or key. This is especially useful for creating variations of types without repeating code, such as making all properties optional, readonly, or changing their types uniformly. The keyof operator helps by giving you all the keys of a type, and generics let you write flexible mapped types that work with any input type.

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

// Basic Mapped Type Example: Make all properties optional

type PartialUser = {
  [Key in keyof User]?: User[Key];
};

// Usage example:
const user1: PartialUser = { name: "Alice" }; // valid because all props optional

// Another example: Make all properties readonly

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

const user2: ReadonlyUser = { id: 1, name: "Bob", age: 25 };
// user2.name = "Charlie"; // Error: Cannot assign to 'name' because it is a read-only property.

To use mapped types properly, start by identifying the base type you want to modify. Use the keyof operator to get all keys of this type, and then create a new type with a mapping expression like [Key in keyof Type]. Inside this mapping, you can apply modifiers such as optional (?) or readonly, or even transform property types by assigning a new type to User[Key]. Combining mapped types with utility types like Partial or Readonly can simplify your code even further, while generics help make your mapped types reusable for many types instead of hardcoding one.

Beginners often make a few common mistakes when working with mapped types. One is forgetting to use the keyof operator, which leads to errors because the compiler doesn’t know the keys to iterate over. Another is mixing syntax or missing the brackets around the mapped type key, which can cause parsing issues. Also, not using generics when you want a flexible mapped type can limit reusability and cause duplication. Lastly, applying modifiers incorrectly, like forgetting the question mark to make properties optional, may result in unexpected type errors in your code.

In summary, TypeScript mapped types are an elegant way to transform existing types by iterating over their properties and creating new variations. They reduce repetitive code when combined with related concepts such as keyof operator, utility types, and generics. With practice, you can use mapped types to build complex and maintainable type systems for your projects. Remember to start simple, test your mappings, and watch out for common syntax pitfalls to leverage the full power of TypeScript’s static typing.