导读:本期聚焦于小伙伴创作的《如何用TypeScript实现类型安全的通用分组求和函数?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何用TypeScript实现类型安全的通用分组求和函数?》有用,将其分享出去将是对创作者最好的鼓励。

使用 TypeScript 实现类型安全的通用分组求和函数

在前端业务开发中,我们经常会遇到需要对数组数据按某个字段分组,再对分组内的数值字段求和的场景。比如按商品类别统计总销量、按用户部门统计薪资总和等。如果使用普通的 JavaScript 实现,很容易因为字段类型错误、参数传参不规范导致运行时问题。本文将介绍如何使用 TypeScript 实现一个类型安全的通用分组求和函数,在编译阶段就规避大部分类型错误。

需求分析

我们需要实现的函数需要满足以下要求:

  • 支持任意类型的数组数据作为输入
  • 支持指定任意字段作为分组依据,且该字段必须是数组元素的属性
  • 支持指定任意数值字段作为求和依据,且该字段必须是数组元素的数值类型属性
  • 分组结果以对象形式返回,键为分组字段的值,值为对应分组内数值字段的总和
  • 全程类型提示,避免传入不存在的字段或非数值字段导致错误

核心实现思路

TypeScript 的泛型和 keyof 操作符是实现类型安全的核心。我们可以通过泛型约束输入数组的元素类型,使用 keyof 限制分组字段和求和字段必须是元素自身的属性,再通过条件类型判断求和字段的类型是否为 number,从而在编译阶段就校验参数合法性。

完整代码实现

下面是完整的 TypeScript 实现代码,包含详细的类型注解和逻辑注释:

// 定义一个工具类型,用于筛选对象中值为 number 类型的键
type NumberKeys<T> = {
  [K in keyof T]: T[K] extends number ? K : never;
}[keyof T];

/**
 * 通用分组求和函数
 * @template T 数组元素的类型
 * @param list 待处理的数组数据
 * @param groupKey 分组依据的字段,必须是 T 类型的属性
 * @param sumKey 求和依据的字段,必须是 T 类型中值为 number 的属性
 * @returns 分组求和结果,键为分组字段的值,值为求和结果
 */
function groupSum<T extends Record<string, any>>(
  list: T[],
  groupKey: keyof T,
  sumKey: NumberKeys<T>
): Record<string, number> {
  // 初始化结果对象
  const result: Record<string, number> = {};

  for (const item of list) {
    // 获取分组字段的值,作为结果的键
    const groupValue = String(item[groupKey]);
    // 获取当前元素的求和字段值
    const sumValue = item[sumKey];

    // 如果结果中还没有该分组,初始化为0
    if (!result.hasOwnProperty(groupValue)) {
      result[groupValue] = 0;
    }
    // 累加求和值
    result[groupValue] += sumValue;
  }

  return result;
}

代码解析

首先我们看工具类型 NumberKeys<T>,它通过映射类型遍历 T 的所有属性,只有属性值为 number 类型的键才会被保留,最终得到 T 中所有数值类型属性的联合类型。这样在传入 sumKey 参数时,TypeScript 会自动提示只能选择数值类型的字段,避免传入字符串等其他类型的字段。

函数本身使用泛型 T 约束数组元素的类型,groupKey 被限制为 T 的任意属性键,sumKey 则被限制为 T 中数值类型的属性键。在函数内部,我们遍历输入数组,取出每个元素的分组字段值作为结果键,累加对应数值字段的值,最终返回分组求和的结果。

使用示例

下面通过几个实际场景的示例,展示这个函数的使用方法:

示例1:商品销量分组统计

// 定义商品数据类型
interface GoodsItem {
  id: number;
  name: string;
  category: string;
  sales: number;
  price: number;
}

// 模拟商品数据
const goodsList: GoodsItem[] = [
  { id: 1, name: '手机', category: '数码', sales: 100, price: 2999 },
  { id: 2, name: '电脑', category: '数码', sales: 50, price: 6999 },
  { id: 3, name: '衬衫', category: '服装', sales: 200, price: 199 },
  { id: 4, name: '裤子', category: '服装', sales: 150, price: 299 },
];

// 按 category 分组,统计 sales 总和
const categorySalesSum = groupSum(goodsList, 'category', 'sales');
console.log(categorySalesSum);
// 输出: { 数码: 150, 服装: 350 }

// 按 category 分组,统计 price 总和
const categoryPriceSum = groupSum(goodsList, 'category', 'price');
console.log(categoryPriceSum);
// 输出: { 数码: 9998, 服装: 498 }

示例2:错误传参的类型提示

如果传入不符合要求的参数,TypeScript 会在编译阶段直接报错:

// 错误1:sumKey 传入非数值类型的字段
// 报错:类型“"name"”的参数不能赋给类型“NumberKeys<GoodsItem>”的参数
groupSum(goodsList, 'category', 'name');

// 错误2:groupKey 传入不存在的字段
// 报错:类型“"invalidKey"”的参数不能赋给类型“keyof GoodsItem”的参数
groupSum(goodsList, 'invalidKey', 'sales');

// 错误3:list 元素类型中不存在对应字段
const wrongList = [{ a: 1 }, { a: 2 }];
// 报错:类型“"b"”的参数不能赋给类型“keyof { a: number }”的参数
groupSum(wrongList, 'b', 'a');

总结

通过 TypeScript 的泛型和类型工具,我们实现了一个完全类型安全的通用分组求和函数。这个函数不仅可以在编译阶段规避大部分参数传参错误,还保留了很好的通用性,能够适配各种不同的数据结构。在实际业务中,类似的思路还可以扩展到分组求平均、分组求最大值等场景,只需要调整对应的聚合逻辑即可,类型约束部分可以复用相同的模式。

TypeScript分组求和泛型编程类型安全前端数据处理 本作品最后修改时间:2026-05-22 16:22:59

免责声明:网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。