How can I map the values within a readonly array to another array using a mapping object within the typescript type system?

Advertisements

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.

Leave a Reply Cancel reply