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

TypeScript中如何用泛型对象与键类型作为字典键实现去重函数

泛型数组按指定键去重的字典实现问题

我想编写一个函数,能够利用对象的任意键过滤泛型数组并返回唯一项。TypeScript允许将T[Key]用作数组类型,但不允许将其用作字典的键。

可行的数组版本代码

const unique = <T, Key extends keyof T>(array: T[], key: Key): T[] => {
  var uniqueArray: T[Key][] = []
  var distinct: T[] = []

  for (var i = 0; i < array.length; i++) {
    if (!uniqueArray.includes(array[i][key])) {
      distinct.push(array[i])
      uniqueArray.push(array[i][key])
    }
  }

  return distinct
}

export default unique

报错的字典版本代码

const unique = <T, Key extends keyof T>(array: T[], key: Key): T[] => {
  var uniqueDict: {[T[Key]]: number} = {}
  var distinct: T[] = []

  for (var i = 0; i < array.length; i++) {
    if (!uniqueDict[array[i][key]]) {
      distinct.push(array[i])
      uniqueDict[array[i][key]] = 1
    }
  }

  return distinct
}

export default unique

报错信息

  • 第一种写法报错:A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1170)
  • 改成{[id: T[Key]]: number}后报错:An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.ts(1337)

解决方案

方案一:使用Record工具类型

Record<K, V>是TypeScript内置的映射类型,可定义键类型为K、值类型为V的对象。结合类型断言处理泛型键的兼容性:

const unique = <T, Key extends keyof T>(array: T[], key: Key): T[] => {
  var uniqueDict: Record<T[Key] extends string | number | symbol ? T[Key] : never, number> = {} as Record<T[Key], number>
  var distinct: T[] = []

  for (var i = 0; i < array.length; i++) {
    const currentKey = array[i][key]
    if (!uniqueDict[currentKey as keyof typeof uniqueDict]) {
      distinct.push(array[i])
      uniqueDict[currentKey as keyof typeof uniqueDict] = 1
    }
  }

  return distinct
}

export default unique

方案二:简化为通用键类型

直接声明字典的键为JS对象允许的类型(string | number | symbol),代码更简洁:

const unique = <T, Key extends keyof T>(array: T[], key: Key): T[] => {
  var uniqueDict: { [key: string | number | symbol]: number } = {}
  var distinct: T[] = []

  for (var i = 0; i < array.length; i++) {
    const currentKey = array[i][key]
    if (!uniqueDict[currentKey]) {
      distinct.push(array[i])
      uniqueDict[currentKey] = 1
    }
  }

  return distinct
}

export default unique

方案三:使用Map替代普通对象

Map支持任意可比较类型作为键,完全适配泛型场景,且性能优于数组includes操作:

const unique = <T, Key extends keyof T>(array: T[], key: Key): T[] => {
  const uniqueMap = new Map<T[Key], T>()
  const distinct: T[] = []

  for (const item of array) {
    const currentKey = item[key]
    if (!uniqueMap.has(currentKey)) {
      uniqueMap.set(currentKey, item)
      distinct.push(item)
    }
  }

  return distinct
}

export default unique

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 16:15:42