user262787
user262787

Reputation: 27

Create Object type from Array type where keys are values of property in each object from array

Given a type that is an array of objects, how do I create a new type that is an object, where the keys are values of a specific property in the array objects, and the values of the object are the type of one of the object generics.

With JS code, it would look like this:

const obj = arr.reduce((acc, element) => ({
  ...acc,
  [element.name]: element.bar
}))

So far I have this:

type ArrayToObject<Arr extends Array<CustomType<any>> = []> = {
  [K in keyof Arr]: ExtractCustomTypeGeneric<Arr[K]>
}

type ExtractCustomTypeGeneric<A> = A extends CustomType<infer T> ? T : never;

type CustomType<T> = {
  name: string,
  foo: number,
  bar: T
}

This gives me an array object (since K in keyof Arr are index numbers), whereas I would want the property keys to be name. Unfortunately something like [Arr[K]['name'] for K in keyof Arr] isn't something that works.

Upvotes: 1

Views: 734

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250376

You can get a union of all the keys in the array using Arr[number]['name'], then you can use Extract to extract from the union of all possible elements in the array (Arr[number]) just the items that have the currently mapped name:

type ArrayToObject<Arr extends Array<CustomType<any>> = []> = {
  [K in Arr[number]['name']]: ExtractCustomTypeGeneric<Extract<Arr[number], { name: K }>>
}

type ExtractCustomTypeGeneric<A> = A extends CustomType<infer T> ? T : never;

type CustomType<T, K = string> = {
  name: K,
  bar: T
}

function createItems<T extends Array<CustomType<any, K>>, K extends string>(...a: T) : T{
    return a;
}

let a = createItems({ name: "A", bar: ""}, { name: "B", bar: 0})

type R = ArrayToObject<typeof a>
//Same as 
type R = {
    A: string;
    B: number;
}

Play

Upvotes: 3

Related Questions