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

TypeScript实现数组对象属性分组计数时索引类型报错问题

问题描述

以下是存在类型报错的TS实现:

export const groupBy = <T, K extends keyof T>(key: K, array: T[]) =>
  array.reduce((objectsByKeyValue, obj) => {
    const value = obj[key];
    objectsByKeyValue[value] = (objectsByKeyValue[value] || 0) + 1;
    return objectsByKeyValue;
  }, {});

相关需求与问题:

  • 类型约束要求:仅允许传入数组内对象类型所包含的属性键作为入参
  • 预期功能:传入对象数组后,按对象的指定属性对元素分组,统计各属性值对应的出现次数
  • 当前报错:实现第4行抛出TS类型错误:Type 'T[K]' cannot be used to index type '{}'.
错误原因

报错根源是reduce方法传入的初始值是无类型标注的空对象{},TS默认将其推断为无任何索引签名的空对象类型,既不支持用T[K]类型的键做索引访问,也未声明存储的属性值为数字类型,因此触发类型校验错误。
另外原类型定义缺少对分组属性取值的约束:JS仅支持string | number | symbol类型作为对象键,如果传入的属性值是对象、数组等类型,会被隐式转换为"[object Object]"这类字符串,导致统计结果异常,需要在类型层做拦截。

修复后实现
export const groupBy = <T, K extends keyof T>(
  key: T[K] extends PropertyKey ? K : never,
  array: T[]
): Record<T[K], number> =>
  array.reduce((objectsByKeyValue, obj) => {
    const value = obj[key];
    objectsByKeyValue[value] = (objectsByKeyValue[value] || 0) + 1;
    return objectsByKeyValue;
  }, {} as Record<T[K], number>);

修复点说明

  • 新增入参类型校验:仅当指定属性的取值为合法对象键(PropertyKey,即string | number | symbol)时,该属性名才允许作为入参传入,非法属性会在TS校验阶段直接报错,满足入参约束要求
  • 给reduce初始值添加类型断言,标记为Record<T[K], number>类型,明确该对象的键为所选属性的取值类型、值为统计用的数字,解决空对象无法被T[K]索引的类型错误
  • 明确标注函数返回值类型,调用函数时可直接获得完整类型提示,无需额外做类型断言

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:54:09