MattTreichel
MattTreichel

Reputation: 1563

How to use mapped types to map a subset of properties in a nested generic type

I have a type like so:

type Thing = {
  name: string;
  deliveryDate: string;
  stuff: {
    place: string;
    datedContacted: string;
  }
}

That I want to create a mapped type with the same structure out of like so:

type FormThing = {
  name: string;
  deliveryDate: Moment;
  stuff: {
    place: string;
    datedContacted: Moment;
  }
}

I'm looking at TypeScript's "Mapped Types" here: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html, but their examples seem to mostly go over how to convert all the properties of a type to another, not a subset.

I've tried to create a generic typing like so:

type DateFields = {
  deliveryDate: string;
  dateContacted: string;
}

export type Form<T> = T & {
  [Property in keyof DateFields]: Moment;
};

But it just doesn't seem to work as expected. Ideally I make it generic, so I can create a typed method that could handle the conversion of any sublevel of this nested object independently from T to Form<T>.

Upvotes: 0

Views: 1426

Answers (1)

Tal Ohana
Tal Ohana

Reputation: 1138

You can achieve this deep mapped type by first changing DateFields to union of string literals, and then by creating a recursive mapped type

type Thing = {
    name: string;
    deliveryDate: string;
    stuff: {
        place: string;
        dateContacted: string;
    }
}

type DateFields = 'deliveryDate' | 'dateContacted';


type Form<T, Fields> = {
    [K in keyof T]: K extends Fields ? Moment : T[K] extends object ? Form<T[K], Fields> : T[K];
}

Inspect it in this TypeScript playground

Upvotes: 1

Related Questions