Home > Software engineering >  Convert Record to Map in type safe way - TypeScript
Convert Record to Map in type safe way - TypeScript

Time:11-15

This is my function that converts record to map:

type MyReturn<Str> = Map<Str, Map<number, number>>;
export const mapRecordToMap = <MyString extends string>(data: Record<MyString, [number, number][]>)
    : MyReturn<MyString> => {
        const myReturn = new Map<MyString, Map<number, number>>();
        Object.entries(data).forEach(([key, value]) => {
            myReturn.set(key as MyString, new Map(value as [number, number][]));
        });
        
        return myReturn;
};

The problem I have is that I have to use 'as' here:

myReturn.set(key as MyString, new Map(value as [number, number][]));

to have proper type checking. How to avoid that?

Thanks!

CodePudding user response:

You can use extra helper for typing Object.entries:


type Entries<T> = {
    [K in keyof T]: [K, T[K]];
}[keyof T][];

const entries = <Obj,>(obj: Obj) => Object.entries(obj) as Entries<Obj>

export const mapRecordToMap = <MyString extends string>(
    data: Record<MyString, [number, number][]>) =>
    entries(data).reduce((acc, [key, value]) => {
        acc.set(key, new Map(value));
        return acc
    }, new Map<MyString, Map<number, number>>());

Playground

Here you can find more approaches of typing Object.entries

P.S. If you have a deal with [].map, [].reduce, {}.keys, {}.entries and you want narrow return type you almost always need to use as type assertion. This is the minimum evil :D

CodePudding user response:

You only need to add a type argument to Object.Entries:

type MyReturn<Str> = Map<Str, Map<number, number>>;

export const mapRecordToMap = <MyString extends string>(data: Record<MyString, [number, number][]>)
    : MyReturn<MyString> => {
        const myReturn = new Map<MyString, Map<number, number>>();
        Object.entries<[number, number][]>(data).forEach(([key, value]) => {
            myReturn.set(key as MyString, new Map(value));
        });
        
        return myReturn;
};

This may be prettier but effectively it isn't much different from what you did already ... Really your casting is pretty safe, because if the type doesn't match the argument it produces an error. (A sign of unsafe casting is when you have to do something more like as unknown as [number, number][] ...)

  • Related