By utilizing TS3.4 and incorporating const
assertions, I have devised a robust typing method as follows:
function arrayToObject<A, K extends keyof any, V>
(array: readonly A[], mapper: (x: A) => readonly [K, V]): { [P in K]: V } {
const result = {} as { [P in K]: V };
for (const item of array) {
const [key, value] = mapper(item);
result[key] = value;
}
return result;
}
const obj1 = arrayToObject([1, 2, 3] as const, v => [v, v * 2] as const)
// const obj1: {1: number, 2: number, 3: number}
const obj2 = arrayToObject(["a", "b", "c"] as const, k => [k, 0] as const);
// const obj2: {a: 0, b: 0, c: 0}
This approach ensures the preservation of literal key values known to the compiler in the mapper's return type. The current limitation lies in the lack of support for higher rank types except for specific enhancements in generic functions.
const obj3 = arrayToObject(["a","b","c"] as const, k => [k, k] as const)
The challenge remains in defining how the compiler can comprehend that {a: "a", b: "b", c: "c"}
is the expected type instead of the more generalized
{a: "a"|"b"|"c", b: "a"|"b"|"c", c: "a"|"b"|"c"}
. Nonetheless, I wish you success in your endeavors!