Mapped types build on the syntax for index signatures, which are used to declare the types of properties which has not been declared ahead of time:

A mapped type is a generic type which uses a union created to iterate through the keys of one type to create another:

  1. type OptionsFlags<Type> = {
    [Property in keyof Type]: boolean;
    };
  1. type FeatureFlags = {
    darkMode: () => void;
    newUserProfile: () => void;
    };
  2. type FeatureOptions = OptionsFlags<FeatureFlags>;
    // ^ = type FeatureOptions = {
  3. // darkMode: boolean;
  4. // }

There are two additional modifiers which can be applied during mapping: readonly and ? which affect mutability and optionality respectively.

You can remove or add these modifiers by prefixing with or +. If you don’t add a prefix, then + is assumed.

  1. // Removes 'optional' attributes from a type's properties
    type Concrete<Type> = {
    [Property in keyof Type]-?: Type[Property];
    };
  2. type MaybeUser = {
    id: string;
    name?: string;
    age?: number;
    };
  3. type User = Concrete<MaybeUser>;
    // ^ = type User = {
  4. // id: string;
  5. // name: string;
  6. // age: number;

Key Remapping via as

  1. ts

You can leverage features like to create new property names from prior ones:

You can filter out keys by producing never via a conditional type:

  1. // Remove the 'kind' property
    type RemoveKindField<T> = {
    [K in keyof T as Exclude<K, "kind">]: T[K]
    };
  2. interface Circle {
    kind: "circle";
    radius: number;
    }
  3. type KindlessCircle = RemoveKindField<Circle>;
    // ^ = type KindlessCircle = {
  4. // radius: number;
  5. // }

Further Exploration

  1. ts
    type ExtractPII<Type> = {
    [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false;
    };
    type DBFields = {
    id: { format: "incrementing" };
    name: { type: string; pii: true };
    };
    type ObjectsNeedingGDPRDeletion = CreateMutable<DBFields>;