Home > Back-end >  Generic type to replace all keys of an object with a mapping
Generic type to replace all keys of an object with a mapping

Time:06-23

I am trying to create a generic type to replace all keys of an object type with a mapping.

Let says we have :

type Input = {
  foo: string
  bar: string
}

And a mapping :

enum Mapping {
  foo = "foo2",
  bar = "bar2",
  otherkey = "otherkey2,
  ....lots of other properties
}

I would like a generic type GenericType so that GenericType<Input> is equal to:

{
  foo2: string
  bar2: string
}

And if possible, I would like to be recursive so that the objects inside Input are also remapped.

Could you help me doing that? Thank you for your answer.

CodePudding user response:

You can use a mapping utility like MapKeys below:

TypeScript Playground

type MapKeys<
  KeyMap extends Record<string, string>,
  T extends Record<string, unknown>,
> = {
  [K in keyof T as K extends keyof KeyMap ? KeyMap[K] : K]:
    T[K] extends Record<string, unknown>
      ? MapKeys<KeyMap, T[K]>
      : T[K];
};

type Input = {
  foo: string;
  bar: string;
  baz: string;
};

const keyMap = {
  foo: 'foo2',
  bar: 'bar2',
} as const;

type KeyMap = typeof keyMap;
type Output = MapKeys<KeyMap, Input>; /*
{
  foo2: string;
  bar2: string;
  baz: string; // Key wasn't in the map, so not modified
}
*/

type InputNested = {
  foo: string;
  bar: {
    foo: number;
    bar: number;
    baz: number;
  };
  baz: string;
};

type OutputNested = MapKeys<KeyMap, InputNested>; /*
{
  foo2: string;
  bar2: {
    foo2: number;
    bar2: number;
    baz: number; // Key wasn't in the map, so not modified
  };
  baz: string;
}
*/


// And if you want to use an enum (but I suggest that you don't):

enum KeyMap2 {
  foo = 'foo2',
  bar = 'bar2',
}

type Output2 = MapKeys<typeof KeyMap2, Input>; /*
                       ^^^^^^
Use "typeof" to get the type of the enum itself */

CodePudding user response:

If you want the shortest possible way, its:

type Genetic<T> = {
  [K in keyof T as K extends keyof typeof Mapping ? typeof Mapping[K] : K]: T[K];
};

type Foo = Genetic<Input>;
  • as let's you remap the type into some other type
  • as supports extends to become conditional to check existence
  • Related