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

TypeScript使用泛型做索引时算术运算报错的原因是什么?

报错原因

TypeScript 对泛型函数的类型检查在函数定义阶段执行,不会结合后续的调用场景推导类型:

  • 你定义的泛型签名为function sortBy<K extends keyof T, T>(vals: T[], key: K): T[],其中T没有任何类型约束,可以是任意类型,对应的T[K]也可以是字符串、对象、函数等任意类型,而算术减法运算仅支持作用在number/bigint/枚举等类型上操作,因此在函数定义阶段就会抛出类型错误。
  • 你编写的非泛型版本没有报错,是因为此时T被固定为Point类型,key的取值范围是x | y,对应的属性值都是number类型,完全符合减法运算的类型要求。

你可能会疑惑调用时传入的是Point类型数组,为什么类型检查器不识别?因为泛型函数需要保证对所有符合签名的调用场景都合法,不会只针对某一次调用的传参类型放宽校验规则,在你没有明确约束T[K]为数字类型的前提下,类型检查器必须假设T[K]可能为任意不可进行算术操作的类型。

无需断言为any的解决方案

方案1:约束泛型仅支持数字类型字段排序

直接给泛型增加类型约束,明确要求传入的T类型中,K对应的属性值必须是number类型即可:

interface Point {
  x: number
  y: number
}

// 调整泛型约束,要求T的K属性类型为number
function sortBy<K extends PropertyKey, T extends Record<K, number>>(vals: T[], key: K): T[] {
  return vals.sort((a, b) => {
    return b[key] - a[key]
  })
}

const pts: Point[] = [
  { x: 1, y: 1 },
  { x: 2, y: 0 },
]

console.log(sortBy(pts, "x"))

方案2:支持通用类型字段排序

如果需要兼容字符串、日期等更多类型的字段排序,可以扩展为支持传入自定义比较函数的版本:

function sortBy<K extends keyof T, T>(
  vals: T[],
  key: K,
  compare?: (a: T[K], b: T[K]) => number
): T[] {
  // 默认比较规则:对数字类型做减法比较
  const defaultCompare = (a: T[K], b: T[K]) => 
    (b as unknown as number) - (a as unknown as number)
  return vals.sort((a, b) => 
    compare?.(a[key], b[key]) ?? defaultCompare(a[key], b[key])
  )
}

// 数字类型字段调用方式不变
console.log(sortBy(pts, "x"))

// 字符串类型字段可以传入自定义比较函数
const users = [{name: '张三'}, {name: '李四'}]
console.log(sortBy(users, 'name', (a, b) => a.localeCompare(b)))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 13:36:04