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:
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