我不会对数组元素使用泛型类型参数T,而是使用泛型来描述键。
我们并不关心列表元素的所有细节。我们只需要知道list 中的每个元素都是一个对象(包括数组),它有一个属性T,其值为number。
我们必须确保:
-
key 是T
T extends PropertyKey
-
list 是 Array
-
list 的元素是{ [K in T]: number } 又名Record<T, number>
function sumByKey<T extends PropertyKey>(list: { [K in T]: number }[], key: T) {
return list.reduce((sum, item) => sum + item[key], 0);
}
现在函数没有错误,因为item[key] 必须是number。
在编写内联列表时存在一些限制。
这很好:
const data = [{x: 30, a: 20}, {x: 50, b: 20}];
const sum = sumByKey(data, 'x');
但这会报错:
const sum = sumByKey([{x: 30, a: 20}, {x: 50, b: 20}], 'x');
键入'{ x:数字;一个号码; }' 不可分配给类型 '{ x: number; }'。
对象字面量只能指定已知属性,并且 'a' 不存在于类型 '{ x: number; }'
如果您想避免此错误,您可以更改list 的定义,使其具有属性T: number 以及任何数量的其他未知属性。
function sumByKey<T extends PropertyKey>(
list: ({ [K in T]: number } & { [K in PropertyKey]?: unknown })[],
key: T
) {
return list.reduce((sum, item) => sum + item[key], 0);
}
现在两者都可以正常工作。
TypeScript Playground Link