I’m having a bit of issue creating a type that maps the values within a readonly array to different values.
I’m making some progress and I’ve now got the following type.
const test = ['Hello', 'Hello_There'] as const;
export type RenameBy<Input extends readonly string[], Map extends Partial<Record<Input[number], unknown>>> = keyof {
[K in Input[number] as K extends keyof Map ? (Map[K] extends string ? Map[K] : never) : K]: never;
};
// "hello" | "helloThere"
type Renamed = RenameBy<typeof test, { Hello: 'hello'; Hello_There: 'helloThere' }>;
As you can see, I’m making it into an object then retrieving the keys as that’s all I need. I’m wondering if there’s a nicer way to do this?
And if not, how can I then convert a union type back into a readonly array? Any help would be much appreciated!
** Edit **
Okay I was making it much harder for myself. I now have the following type which is nicer. it still outputs a union not a new readonly array which is what I want
export type RenameBy<
Input extends readonly string[],
Map extends Partial<Record<Input[number], unknown>>,
> = Map[Input[number]] extends string ? Map[Input[number]] : Input[number];
>Solution :
It seems like you’re looking for a way to map the values within a readonly array to another array using a mapping object within the TypeScript type system. Here’s one approach you could take:
const test = ['Hello', 'Hello_There'] as const;
type Map<T extends readonly string[]> = { [K in T[number]]: string };
type RenameBy<T extends readonly string[], M extends Map<T>> = {
[K in keyof M]: K extends T[number] ? M[K] : never;
};
type Renamed = RenameBy<typeof test, { Hello: 'hello'; Hello_There: 'helloThere' }>;
type RenamedArray = ReadonlyArray<Renamed[keyof Renamed]>;
const renamedArray: RenamedArray = ['hello', 'helloThere'];
First, we define a Map
type that takes in a readonly string array T
and maps each string in the array to a string value.
Next, we define the RenameBy type, which takes in a readonly string array T
and a mapping object M
that maps values in T
to new values. We create a new object type that maps each key in M
to the new value in M
if the key is present in T
, and never otherwise.
Finally, we use the keyof operator to get a union type of all the keys in the resulting object, and we use that union type to define a new readonly array type RenamedArray that contains the new values from the mapping object.
You can see in the example above that RenamedArray
is inferred to be ReadonlyArray<"hello" | "helloThere">
, which is the desired output.