Home > front end >  Pick keys from a Typescript interface and change their types
Pick keys from a Typescript interface and change their types

Time:05-22

I have this interface:

export interface MutationSheetDefinition {
    _type: "mutation.sheet.definition"
    id: string
    name: string
    mutations: MutationDefinition[]
    referencedMutationSheets: MutationSheetReference[]
}

and I want this type:

interface ValidatedMutationSheetDefinition {
    name: ValidationOf<string>
    mutations: ValidationOf<MutationDefinition>[]
    referencedMutationSheets: ValidationOf<MutationSheetReference>[]
}

I know I can pick our a subset of the interface using this:

type narrowed = Pick<MutationSheetDefinition, "name"| "mutations" | "referencedMutationSheets">

which will give me

interface {
    name: string
    mutations: MutationDefinition[]
    referencedMutationSheets: MutationSheetReference[]
}

But can I change the types of the picked keys?

I would settle for a fixed type for all picked keys, so this would do:

interface {
    name: Validation
    mutations: Validation[]
    referencedMutationSheets: Validation[]
}

CodePudding user response:

You can do it like this:

type PickAndChangeToValidationOf<T, P extends keyof T> = {
  [K in P]: T[K] extends (infer I)[] 
    ? ValidationOf<I>[]
    : ValidationOf<T[K]> 
}

I was not sure how you want arrays handled. In your example, you removed the [] and put it behind ValidationOf<T>. The type above does this too, but only for the first level of arrays. If you want different behaviour for double nested arrays, you should specify so.

Usage:

interface MutationSheetDefinition {
    _type: "mutation.sheet.definition"
    id: string
    name: string
    mutations: number[]
    referencedMutationSheets: number[]
}

type Narrowed = PickAndChangeToValidationOf<MutationSheetDefinition, "name"| "mutations" | "referencedMutationSheets">
// type Narrowed = {
//     name: ValidationOf<string>;
//     mutations: ValidationOf<number>[];
//     referencedMutationSheets: ValidationOf<number>[];
// }

Playground

CodePudding user response:

There you are (I swapped your custom types with random strings, just remove them):

type MutationDefinition = "MutationDefinition";
type MutationSheetReference = "MutationSheetReference";

export interface MutationSheetDefinition {
  _type: "mutation.sheet.definition"
  id: string
  name: string
  mutations: MutationDefinition[]
  referencedMutationSheets: MutationSheetReference[]
}

type Narrowed = Pick<MutationSheetDefinition, "name"| "mutations" | "referencedMutationSheets">;

type Validation = "Validation";

type Validational<Type> = {
  [Property in keyof Type]: Type[Property] extends unknown[] ? Validation[] : Validation;
};

type Definition = Validational<Narrowed>;

const d: Definition = {
  name: "Validation",
  mutations: ["Validation", "Validation"],
  referencedMutationSheets: ["Validation", "Validation"],
}

A drawback of this solution is that it has types hardcoded to only array and all other things. You'll have to add more types if you use any other types, i.e. an array of arrays will need to be added.

CodePudding user response:

type ValidatedMutationSheetDefinition = {
  [key in keyof narrowed]: MutationSheetDefinition[key] extends Array<(infer U)> ? Array<ValidationOf<U>> : ValidationOf<narrowed[key]>
}
  • Related