You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript泛型中为两个键分别指定不同类型?

问题:TypeScript中如何定义「group-by-and-sum」函数的泛型类型?

我正在编写一个针对JavaScript对象的「group-by-and-sum」函数,代码如下:

function groupBySum<
  GroupByKey extends string,
  SumKey extends string,
  Record extends ???
>(groupBy: GroupByKey, sumOver: SumKey, records: Record[]): Map<R[GroupByKey], number>{
   ...
}

调用示例如下:

>> groupBySum('color', 'age', cats)
Map('black' => 3, 'orange' => 2, 'white' => 4)

其中groupBy对应的属性可以是任意类型,但sumOver对应的属性必须是number类型。请问此处Record的类型应该如何定义?或者更通用地说,该如何定义这些泛型类型?


解决方案

你可以通过泛型约束明确Record的结构,要求它必须包含GroupByKey和SumKey两个属性,且SumKey对应的属性值类型为number,GroupByKey对应的属性值可以是任意可哈希类型(Map键支持这类类型)。同时需要修正返回类型中错误的R,改为Record:

function groupBySum<
  GroupByKey extends string,
  SumKey extends string,
  Record extends { [K in GroupByKey]: unknown } & { [K in SumKey]: number }
>(groupBy: GroupByKey, sumOver: SumKey, records: Record[]): Map<Record[GroupByKey], number> {
  return records.reduce((map, item) => {
    const key = item[groupBy];
    const currentSum = map.get(key) || 0;
    map.set(key, currentSum + item[sumOver]);
    return map;
  }, new Map<Record[GroupByKey], number>());
}

泛型说明

  • GroupByKey extends string:限定分组用的属性名必须是字符串类型(符合对象键的常规场景)
  • SumKey extends string:限定求和用的属性名必须是字符串类型
  • Record extends { [K in GroupByKey]: unknown } & { [K in SumKey]: number }:
    • 第一个交叉类型{ [K in GroupByKey]: unknown }确保Record包含GroupByKey指定的属性,属性值类型不限
    • 第二个交叉类型{ [K in SumKey]: number }确保Record包含SumKey指定的属性,且属性值必须是number类型
  • 返回类型Map<Record[GroupByKey], number>:明确返回的Map的键类型与原对象中分组属性的类型一致,值为求和后的数字

类型安全验证

当传入不符合要求的参数时,TypeScript会自动报错:

  • 如果sumOver指定的属性不是number类型(比如传入对应字符串类型的'name'),TS会提示类型不匹配
  • 如果传入的records数组中存在对象缺少groupBy或sumOver指定的属性,TS也会给出错误提示

内容的提问来源于stack exchange,提问作者Sasgorilla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:30:30