Mapped Types

Back

Loading concept...

🗺️ Mapped Types: The Magic Copy Machine

Imagine you have a magical photocopier. But this isn’t an ordinary copier—it can change things while copying! Want all your homework answers to become questions? This copier can do that. Want to make everything optional? Done!


🎯 What Are Mapped Types?

Think of a mapped type like a recipe transformer. You give it one recipe, and it creates a new recipe by changing every ingredient in a specific way.

Simple Example: The Cookie Box

Imagine you have a box of cookies:

type CookieBox = {
  chocolate: string;
  vanilla: string;
  strawberry: string;
};

Now, you want to know: “Did I eat each cookie?” You need a new box that tracks if each cookie was eaten:

type AteTheCookie = {
  [Cookie in keyof CookieBox]: boolean;
};

// Result:
// {
//   chocolate: boolean;
//   vanilla: boolean;
//   strawberry: boolean;
// }

What happened? The mapped type went through EACH cookie and changed its type from string to boolean!


🔑 The Magic Formula

type NewType = {
  [Key in keyof OriginalType]: NewValueType;
};

Let’s break this down like a sandwich:

graph TD A["[Key in keyof T]"] --> B["Go through each key"] B --> C["For EACH key..."] C --> D["Create a new property"] D --> E["With the new type you specify"]
Part What It Does
[Key in keyof T] Loop through all keys in T
: Assign a new type
NewType What each value becomes

🎚️ Mapping Modifiers: Adding Superpowers

Modifiers are like magic words that change properties. There are two main ones:

1. The ? Modifier (Optional)

Makes properties optional (you don’t have to fill them in).

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

// Make everything optional
type MaybeAPerson = {
  [Key in keyof Person]?: Person[Key];
};

// Result:
// {
//   name?: string;
//   age?: number;
// }

2. The readonly Modifier (Read-Only)

Makes properties unchangeable (like writing with permanent marker).

type LockedPerson = {
  readonly [Key in keyof Person]: Person[Key];
};

// Result:
// {
//   readonly name: string;
//   readonly age: number;
// }

➖ Removing Modifiers: The Minus Sign

What if you want to REMOVE these modifiers? Use the minus sign -!

Remove Optional (-?)

type RequiredPerson = {
  [Key in keyof MaybeAPerson]-?: MaybeAPerson[Key];
};

// Takes optional properties
// and makes them REQUIRED again!

Remove Readonly (-readonly)

type UnlockedPerson = {
  -readonly [Key in keyof LockedPerson]: LockedPerson[Key];
};

// Takes readonly properties
// and makes them CHANGEABLE again!

🎨 Adding Modifiers: The Plus Sign

You can also use + to explicitly ADD modifiers (though it’s optional):

// These are the same:
type A = { [K in keyof T]?: T[K] };
type B = { [K in keyof T]+?: T[K] };

Think of + as saying “YES, definitely add this!”


🏷️ Key Remapping: Rename While You Copy

This is where things get REALLY cool! You can rename keys as you copy them.

The as Keyword

type Getters = {
  [Key in keyof Person as `get${Capitalize<Key>}`]:
    () => Person[Key];
};

// Result:
// {
//   getName: () => string;
//   getAge: () => number;
// }

What happened?

  • name became getName
  • age became getAge
graph TD A["Original: name, age"] --> B["Add &&#35;39;get&&#35;39; prefix"] B --> C["Capitalize first letter"] C --> D["getName, getAge"]

🗑️ Filtering Keys: Remove What You Don’t Want

Use never to SKIP certain keys:

type RemoveAge = {
  [Key in keyof Person as
    Key extends 'age' ? never : Key
  ]: Person[Key];
};

// Result:
// {
//   name: string;
//   // age is GONE!
// }

It’s like saying: “Copy everything… EXCEPT age!”


🎁 Built-in Helpers (TypeScript Gives You These!)

TypeScript already has these mapped types ready for you:

Helper What It Does
Partial<T> Makes all properties optional
Required<T> Makes all properties required
Readonly<T> Makes all properties readonly
Pick<T, K> Picks only certain properties
Omit<T, K> Removes certain properties
Record<K, T> Creates a type with keys K and values T

How They Work Inside

// Partial (built-in)
type Partial<T> = {
  [K in keyof T]?: T[K];
};

// Required (built-in)
type Required<T> = {
  [K in keyof T]-?: T[K];
};

// Readonly (built-in)
type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

🧪 Real-World Example: Form States

Imagine you’re building a form:

type UserForm = {
  username: string;
  email: string;
  password: string;
};

// For the "touched" state (which fields did user click?)
type TouchedFields = {
  [K in keyof UserForm]: boolean;
};

// For error messages
type FormErrors = {
  [K in keyof UserForm]?: string;
};

// For loading states per field
type LoadingStates = {
  [K in keyof UserForm as `${K}Loading`]: boolean;
};
// Result: { usernameLoading: boolean; ... }

🌟 The Big Picture

graph TD A["Original Type"] --> B["Mapped Type"] B --> C["Loop through keys"] C --> D{"What to do?"} D --> E["Change value type"] D --> F["Add/Remove modifiers"] D --> G["Rename keys"] E --> H["New Type!"] F --> H G --> H

✨ Summary: Your Mapped Types Toolkit

Concept Syntax Effect
Basic Mapping [K in keyof T] Copy structure
Change Type : NewType Transform values
Add Optional ? or +? Properties optional
Remove Optional -? Properties required
Add Readonly readonly or +readonly Can’t change
Remove Readonly -readonly Can change again
Rename Keys as NewKey New property names
Filter Keys as ... ? never : Key Remove properties

🚀 You Did It!

You now understand mapped types—the powerful feature that lets you:

  1. Copy and transform entire types at once
  2. Add or remove optional/readonly modifiers
  3. Rename keys while copying
  4. Filter out properties you don’t want

It’s like having a magical copy machine that can do ANYTHING! 🎉

Remember: Mapped types help you avoid repeating yourself. Instead of writing the same type structure over and over, you write it ONCE and let TypeScript do the transforming!

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.