如何将键/值对象的元组映射到对象?

问题描述 投票:0回答:1

在下面的代码块中,如何重写函数

keyValueArrayToObject
以使
keyValueObject
的类型为
{a: number; b: string}
,而不是当前的
{[k: string]: any}
类型?

const arrayOfKeyValue = [
  {key: 'a', value: 1},
  {key: 'b', value: 'z'},
];

const keyValueArrayToObject = <const T extends readonly {key: PropertyKey; value: any}[]>(
  arr: T
) => {
  return Object.fromEntries(arr.map(o => [o.key, o.value]));
};

const keyValueObject = keyValueArrayToObject(arrayOfKeyValue);
typescript tuples typescript-generics
1个回答
0
投票

您可以在映射类型中使用键重新映射来迭代arr

数组的元素类型的
union
,并且对于联合的每个成员
U,您可以索引到
该成员的
key
value

属性来获取映射属性的键和值:
const keyValueArrayToObject = <const T extends readonly { key: PropertyKey; value: any }[]>(
  arr: T
) => {
  return Object.fromEntries(arr.map(o => [o.key, o.value])) as
    { [U in T[number] as U['key']]: U['value'] };
};

我们需要一个 类型断言,因为 TypeScript 没有足够的强类型

Object.fromEntries()


现在我们可以针对您的示例进行测试:
const arrayOfKeyValue = [
  { key: 'a', value: 1 },
  { key: 'b', value: 'z' },
] as const; // <-- need this

const keyValueObject = keyValueArrayToObject(arrayOfKeyValue);
/* const keyValueObject: {
    a: 1;
    b: "z";
} */

看起来不错,尽管与您要求的略有不同。首先,您需要在数组文字上使用

const 断言
 或类似的东西。否则 TypeScript 会推断出像 
Array<{key: string, value: string} | {key: string, value: number}> 这样的宽类型。这种类型并没有错,但它对于您的需求来说不够具体。您需要编译器至少跟踪 key
 属性的
文字类型

通过 
const
 断言,您还可以获得 
value
 属性的文字类型,因此 
keyValueObject
 被推断为具有 
{a: 1, b: "z"} 类型。如果这太具体了,那么您需要手动加宽它,或者对数组文字类型进行更多控制,例如 [{ key: 'a' as const, value: 1 },{ key: 'b' as const, value: 'z' }]
 或更奇怪的 
[{key: 'a', value: 1},{key: 'b', value: 'z'}] satisfies ({ key: "xxx" | (string & {}), value: unknown })[]
。但我认为这超出了所提出问题的范围。

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.