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

TypeScript泛型求和函数类型守卫失效问题及无any实现方案

TypeScript泛型汇总函数类型守卫失效问题解决

问题描述

我编写了TypeScript泛型函数getTotal,用于根据对象数组生成汇总对象:对对象的数值类型属性求和,非数值属性保持原值。但使用typeof类型守卫后,直接执行acc[key] = item[key] + acc[key]仍触发ESLint类型错误,临时用any兼容但实现不优雅。现请教:

  1. 为何该类型守卫无法将acc[key]识别为number类型?
  2. 如何不使用any完成该功能?

问题1:类型守卫无法识别acc[key]为number的原因

TypeScript的静态类型检查在处理泛型索引访问时存在局限性:当key是泛型类型T的联合键(keyof T)时,typeof item[key] === 'number'只能缩小item[key]的类型为number,但无法自动关联acc[key]的类型。

这是因为key属于keyof T的联合类型,编译器无法通过遍历逻辑推断出当前key对应的acc[key]和item[key]必然是同类型——即便你明确数组中所有对象结构一致,TypeScript也无法在静态检查阶段确认这一点,因此不会自动将acc[key]的类型缩小为number。


问题2:不使用any的解决方案

方案1:双重类型守卫+安全类型断言

通过同时校验acc[key]和item[key]的类型,确保两者都是number后,用类型断言将求和结果赋值给acc[key]。这种方式在类型守卫的保障下完全安全:

function getTotal<T extends Record<string, unknown>>(arr: T[]): T {
  if (arr.length === 0) return {} as T;

  // 初始化累加器为第一个元素的副本
  const acc = { ...arr[0] } as T;

  for (const item of arr.slice(1)) {
    // 将Object.keys结果断言为keyof T,避免类型丢失
    (Object.keys(acc) as Array<keyof T>).forEach(key => {
      const accVal = acc[key];
      const itemVal = item[key];

      // 同时校验两个值的类型,确保都是number
      if (typeof accVal === 'number' && typeof itemVal === 'number') {
        // 类型断言为当前key对应的类型,避免类型不匹配
        acc[key] = accVal + itemVal as typeof acc[key];
      }
      // 非数值属性保持累加器初始值(可按需改为取当前item的值)
    });
  }

  return acc;
}

方案2:预定义数值属性键类型

通过类型工具提取对象中的数值属性键,遍历时分类型处理,进一步提升类型严谨性:

// 类型工具:提取对象T中值为number类型的键
type NumericKeys<T> = {
  [K in keyof T]: T[K] extends number ? K : never;
}[keyof T];

function getTotal<T extends Record<string, unknown>>(arr: T[]): T {
  if (arr.length === 0) return {} as T;

  const acc = { ...arr[0] } as T;

  for (const item of arr.slice(1)) {
    // 处理数值属性:求和
    (Object.keys(acc) as Array<NumericKeys<T>>).forEach(key => {
      acc[key] = (acc[key] as number) + (item[key] as number) as typeof acc[key];
    });

    // 非数值属性保持原值(按需可替换为当前item的值)
  }

  return acc;
}

这种方案通过类型工具提前划分键的类型,让编译器明确知道哪些键对应数值类型,减少类型断言范围,代码可读性和安全性更高。


内容的提问来源于stack exchange,提问作者Lyubomir.Rudko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 01:24:28