Home > Net >  Make keys with specific character in their name optional
Make keys with specific character in their name optional

Time:12-09

Say I have an object like:

const obj = {
  a: 1,
  "b?": 2,
  "c?": 3
}

Its type currently is:

type Obj = {
  a: number;
  "b?": number;
  "c?": number;
}

Is there a way to create a type that accepts obj and converts its type to:

type Obj = {
  a: number;
  b?: number;
  c?: number;
}

Essentially making b and c optional.

CodePudding user response:

You can do it by using template literal types and inference. Breaking it into parts (but we'll combine them at the end):

  1. First we want to get the required properties:

    type MapRequiredKeys<T> = {
        [Key in keyof T as Key extends `${string}?` ? never : Key]: T[Key];
    };
    

    There, if Key matches the pattern ${string}?, we leave it out by using never as the key; otherwise, we use the key. Using that on typeof obj gives us { a: number; }.

  2. Then we want the optional ones, and we want just the base part of the key, not the ?. That's where infer comes in:

    type MapOptionalKeys<T> = {
        [Key in keyof T as Key extends `${infer BaseKey}?` ? BaseKey : never]?: T[Key];
    };
    

    We match Key against ${infer BaseKey}? and then use BaseKey if it matches (leaving out the property entirely if it doesn't). We use ? on it to make the property optional.

  3. Combining them:

    type MapKeys<T> = MapRequiredKeys<T> & MapOptionalKeys<T>;
    
    type ObjType = MapKeys<typeof obj>;
    

    Playground example

But we can combine them into a single type, which makes the hints that TypeScript gives us clearer:

type MapKeys<T> = {
    [Key in keyof T as Key extends `${string}?` ? never : Key]: T[Key];
} & {
    [Key in keyof T as Key extends `${infer BaseKey}?` ? BaseKey : never]?: T[Key];
};

type ObjType = MapKeys<typeof obj>;

Playground example

If you hover ObjType there, you see type ObjType = { a: number; } & { b?: number | undefined, c?: number | undefined; } instead of seeing the "calls" to MapRequiredKeys and MapOptionalKeys.

  • Related