We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Mapped Types

Remember dynamic properties?

type UserMetrics = {
  [key: string]: number;
};

Well, mapped types are a way to create new types with dynamic properties based on existing types. For example, say we have a Soldier type:

type Soldier = {
  name: string;
  age: number;
  branch: "garrison" | "military police" | "survey corps";
};

And we want to create a new type that has the same properties, but all of them are optional. We can do that with a mapped type:

type OptionalSoldier = {
  [K in keyof Soldier]?: Soldier[K];
};
  • The keyof operator gets the keys of the Soldier type
  • The in keyword iterates over them
  • The ? makes each property optional
  • The Soldier[K] gets the value type each property maps to

It results in a type that's the same as:

type OptionalSoldier = {
  name?: string;
  age?: number;
  branch?: "garrison" | "military police" | "survey corps";
};

The obvious benefit, of course, is that if we update Soldier, OptionalSoldier automatically updates too.

Changing the Values

Mapped types are really useful for making properties optional or readonly, but it's an incredibly powerful (and potentially dangerously confusing) tool. You can also use them to change the value type of properties:

type StringifiedSoldier = {
  [K in keyof Soldier]: string;
};

Which is the same as:

type StringifiedSoldier = {
  name: string;
  age: string;
  branch: string;
};

Assignment

The QA team at Support.ai needs to reset form data to a clean state before each test run. You've been asked to:

Tips

To create a new empty object of type Blank<T>, a type assertion is likely the easiest way:

const result = {} as Blank<T>;