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
相关产品推荐
相关产品推荐

