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

如何为TypeScript泛型约束实现`+`运算符,优化sumBy支持bigint

优化sumBy函数以支持number和bigint类型

先给出一个简洁且类型安全的实现,解决你当前的冗余判断和空数组返回类型问题:

type Numeric = number | bigint;
type Zero<T extends Numeric> = T extends number ? 0 : 0n;

export function sumBy<T, U extends Numeric>(
  array: T[],
  mapperFn: (item: T) => U
): U {
  // 处理空数组,返回对应类型的初始值
  if (array.length === 0) {
    return (Zero<U> as unknown) as U;
  }

  return array.reduce((sum, currentItem) => {
    const currentValue = mapperFn(currentItem);
    
    // 类型守卫确保同类型相加,避免number与bigint混用
    if (typeof sum === "number" && typeof currentValue === "number") {
      return sum + currentValue as U;
    }
    if (typeof sum === "bigint" && typeof currentValue === "bigint") {
      return sum + currentValue as U;
    }

    // 理论上不会执行到这里,因为mapperFn返回类型为U,保证类型统一
    throw new Error("Invalid numeric type combination");
  }, mapperFn(array[0]) as U);
}

解答你的两个核心疑问

1. 为什么无法直接告知TypeScript这两种类型都实现了+运算符?

TypeScript的类型系统中不存在“可加法运算”的通用约束,原因有两点:

  • number和bigint是语言内置的原始类型,它们的+支持是硬编码在语言逻辑中的,没有对应的接口或抽象类型可以复用;
  • 这两种类型的加法是互斥的——number + bigint会直接触发类型错误,TS无法为它们定义一个共享的“可加”约束,必须显式区分处理。

2. 为什么不能用U is number or bigint这样的泛型签名?

U is number | bigint是类型谓词的语法,只能用于函数返回值,作用是在运行时缩小变量的类型范围,不能用来定义泛型约束。泛型约束必须使用U extends number | bigint(也就是你最初使用的写法)。

要让TS确保输入输出类型一致,关键是:

  • 用数组第一个元素的映射值作为累加初始值,保证累加器类型与U完全匹配;
  • 通过类型守卫在运行时验证累加器和当前值的类型,避免跨类型相加;
  • 为空数组返回对应类型的初始值(0或0n),消除返回类型中的undefined。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 04:35:58