TypeScript同类型多泛型及listToMap列表转Map函数技术咨询
嘿,你的这个listToMap函数基础逻辑已经很扎实了!针对TypeScript多泛型的扩展需求,我给你整理了几个优化方向和实用方案,一起来看看吧:
优化你的TypeScript
listToMap 函数(多泛型扩展方案) 一、基础优化:让Key类型不再局限于String
你的原函数把Map的key限定为string,但TypeScript的Map本身支持string | number | symbol类型的key。我们可以给key也加一个泛型参数,让函数的复用性直接拉满:
export function listToMap<T, K extends keyof any>( list: T[], keyAccessFn: (element: T) => K ): Map<K, T> { const reducer = (accumulator: Map<K, T>, currentValue: T) => accumulator.set(keyAccessFn(currentValue), currentValue); return list.reduce(reducer, new Map<K, T>()); }
这里K extends keyof any是TypeScript里约束合法Map key类型的常用写法,现在你可以轻松用数字或符号作为key了:
const numList = [{id: 1, name: "Alice"}, {id: 2, name: "Bob"}]; const numKeyMap = listToMap(numList, item => item.id); // 类型为 Map<number, {id: number; name: string}>
二、多泛型进阶:支持自定义值的转换
很多场景下我们不只是想把原元素存进Map,还需要对元素做转换后再存储。这时候可以新增一个泛型V来定义值的类型,同时加一个可选的转换函数:
export function listToMap<T, K extends keyof any, V = T>( list: T[], keyAccessFn: (element: T) => K, valueTransformFn: (element: T) => V = (item) => item as unknown as V ): Map<K, V> { const reducer = (accumulator: Map<K, V>, currentValue: T) => accumulator.set(keyAccessFn(currentValue), valueTransformFn(currentValue)); return list.reduce(reducer, new Map<K, V>()); }
这个版本兼容性拉满:不需要转换值时,还是可以像原来一样只传前两个参数;需要转换时,能灵活生成不同类型的Map:
const userList = [{id: "u1", name: "Alice", age: 30}, {id: "u2", name: "Bob", age: 25}]; const userNameMap = listToMap(userList, item => item.id, item => item.name); // 类型为 Map<string, string>
三、实用增强:处理重复Key的场景
原函数遇到重复key会直接覆盖,这在很多场景下可能不是预期行为。我们可以加一个可选参数,让用户指定重复key的处理策略:
type DuplicateKeyStrategy = 'keep-first' | 'keep-last' | 'collect-array'; export function listToMap<T, K extends keyof any, V = T>( list: T[], keyAccessFn: (element: T) => K, valueTransformFn: (element: T) => V = (item) => item as unknown as V, duplicateStrategy: DuplicateKeyStrategy = 'keep-last' ): Map<K, V | V[]> { const reducer = (accumulator: Map<K, V | V[]>, currentValue: T) => { const key = keyAccessFn(currentValue); const value = valueTransformFn(currentValue); if (accumulator.has(key)) { const existingValue = accumulator.get(key); switch (duplicateStrategy) { case 'keep-first': break; // 保留第一个值,不做操作 case 'keep-last': accumulator.set(key, value); break; case 'collect-array': accumulator.set(key, Array.isArray(existingValue) ? [...existingValue, value] : [existingValue, value]); break; } } else { accumulator.set(key, value); } return accumulator; }; return list.reduce(reducer, new Map<K, V | V[]>()); }
使用示例:
const duplicateList = [{id: 1, name: "Alice"}, {id: 1, name: "Alicia"}, {id: 2, name: "Bob"}]; // 把重复key的元素收集为数组 const collectedMap = listToMap(duplicateList, item => item.id, undefined, 'collect-array'); // 类型为 Map<number, {id: number; name: string}[]>
四、类型安全小细节
在进阶版本中,默认的valueTransformFn用了as unknown as V,这是因为当V默认等于T时,直接返回原元素是类型安全的;如果用户显式指定了不同的V,则需要用户自己保证转换的类型正确性——这在TypeScript的泛型设计里是合理的权衡。
内容的提问来源于stack exchange,提问作者SchreiberLex
相关产品推荐
相关产品推荐

