DEV Community

loading...

Discussion on: How to convert an array into an object in javascript

Collapse
kukuster profile image
Kukuster • Edited

Here's type-friendly version in TypeScript

export function convertArrayToObject
<
T extends { [prop in string | number]: any },
K extends keyof Pick<T, {
    [Key in keyof T]: T[Key] extends string | number ? Key : never
}[keyof T]> = keyof Pick<T, {
    [Key in keyof T]: T[Key] extends string | number ? Key : never
}[keyof T]>,
A extends T[] = T[]
>
(array: readonly T[], key: K)
{
    const initialValue = {};
    return array.reduce((obj, item) => {
        return {
            ...obj,
            [item[key]]: item,
        };
    }, initialValue) as { [propkey in A[number][K]]: A[number]; };
}
Enter fullscreen mode Exit fullscreen mode

Notes:
• TypeScript 4.0+ (tested on 4.0.x and 4.1.x)

• for the 2nd arg TS will allow and suggest only those keys for which all objects hold a value of type number or string (only those types by which any object props can be indexed).
So if all those objects had a prop BD with a string value for all the people, except John's BD was a Date object, TS won't suggest nor allow you to choose 'BD' for the 2nd arg.

• that single usage of any here is intentional. As a result, it's going to be collapsed, whereas using unknown would require several additional checks.

• usage of as operator to assert the type of return value is intentional. May be unnecessary in future TypeScript versions.

• works perfectly for variable data, but only almost perfect for constant data.
Here in this example if you denote that test array as const, TS will be able to tell you that the object has 5 properties 111, 112, 122, 123, 125, but won't be able to tell you which object exactly under each key and think its a union type of all objects for each key.
So, given the passed array had as const annotation and the returned object from the example is called fooobj:

const bar = fooobj[111];
// it thinks bar is of type of one of the objects from the original array

const name = bar.name;
// TS suggests name is of type 'John' | 'Sarah' | 'Kate' | 'Tom' | 'Emma'

if (bar.id === 111){
    // only here types collapse, asserting the exact value for bar props
    const name = bar.name;
    // TS is convinced that name === 'John'
}

Enter fullscreen mode Exit fullscreen mode