Let's suppose I have an array in Typescript, which looks like this:
const array = [['a', 1], ['b', 2], ['c', 3]] as const;
So, its type resolves to:
const array: readonly [readonly ["a", 1], readonly ["b", 2], readonly ["c", 3]]
I want now to create a type that will have keys from the first value from each array, and values from the second value of each array. For the array above, the object should look like this:
type Result = {
a: 1,
b: 2,
c: 3
}
The order of the elements does not matter. The array will always be a const array of two elements, so there is no need for variable-length arrays.
I tried something like this, but to no avail:
type ObjectFromArray<A extends readonly (readonly [string, number])[]> = {
[K in keyof A as A[K][0]]: A[K][1]
};
It always throws me an error:
Type '0' cannot be used to index type 'A[K]'.
So, does anyone know to do something like this?
CodePudding user response:
You were pretty close.
type ObjectFromArray<A extends readonly (readonly [string, number])[]> = {
[K in A[number] as K[0]]: K[1]
};
We can use A[number]
to get a union of all tuples over which we can map. During mapping, you can access K
directly as it represents a single tuple inside the array.
You may be wondering why your approach is not working. Here is a working version, but it is way more verbose than the solution above.
type ObjectFromArray<A extends readonly (readonly [string, number])[]> = {
[K in Exclude<keyof A, number> as A[K][0 & keyof A[K]] & string]: A[K][1 & keyof A[K]]
};
You will need to exclude the type number
from keyof A
, because you only want the three keys 0 | 1 | 2
but not the number
index of an array. We also need a lot of intersections here because TypeScript can't follow our logic anymore because of the Exclude
.