【问题标题】:Generic type for something like Lodash sumbyLodash sumby 之类的通用类型
【发布时间】:2021-08-11 18:09:01
【问题描述】:

你将如何键入一个函数来有效地完成lodash.sumby 对键的作用? DefinitelyTyped types for it 是松散的,没有指定字符串参数需要是集合类型的键。

以下似乎接近了,但它没有指定T[key]的类型是数字

function sumByKey<T>(list: T[], key: keyof T) {
  return list.reduce((sum, item) => sum + item[key], 0);
}

所以它有错误

Operator '+' cannot be applied to types 'number' and 'T[keyof T]'.

【问题讨论】:

    标签: typescript typescript-typings typescript-generics


    【解决方案1】:

    我不会对数组元素使用泛型类型参数T,而是使用泛型来描述键。

    我们并不关心列表元素的所有细节。我们只需要知道list 中的每个元素都是一个对象(包括数组),它有一个属性T,其值为number

    我们必须确保:

    • keyT
    • T extends PropertyKey
    • listArray
    • list 的元素是{ [K in T]: number } 又名Record&lt;T, number&gt;
    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

    【讨论】:

      猜你喜欢
      • 2016-07-22
      • 2021-10-28
      • 2020-08-16
      • 2019-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-09
      • 2017-05-02
      相关资源
      最近更新 更多