TypeScript中如何实现ES6 Map键值类型的关联约束?
TypeScript 实现ES6 Map的键值类型关联约束
原生Map的泛型参数K(键类型)和V(值类型)是独立的,不会做关联校验,所以直接写Map<string | number, number | string>会放行列如<number, number>、<string, string>的不合法组合,无法满足需求。可以通过重载Map核心方法的方式实现键值的关联约束,具体方案如下:
方案1:针对当前需求快速实现
// 定义Map的键值关联规则,同时重载set、get方法 interface RelatedMap extends Map<string | number, number | string> { set<T extends string | number>(key: T, value: T extends string ? number : string): this get(key: string): number | undefined get(key: number): string | undefined } // 实例化时断言为自定义的RelatedMap类型 const map = new Map() as RelatedMap // 校验效果 map.set(1, 'a') // 正常通过 map.set('a', 1) // 正常通过 map.set(1, 1) // 类型报错:类型“number”的参数不能赋给类型“string”的参数 map.set('a', 'a') // 类型报错:类型“string”的参数不能赋给类型“number”的参数 // get方法也能自动推导返回值类型 const val1 = map.get(1) // 类型为:string | undefined const val2 = map.get('a') // 类型为:number | undefined
方案2:通用可扩展的泛型实现
如果后续需要新增更多键值映射规则,可以使用通用泛型工具,适配任意关联规则:
// 通用Map约束泛型,泛型参数传入键值映射关系即可 type ConstrainedMap<T extends Record<any, any>> = { set<K extends keyof T>(key: K, value: T[K]): this get<K extends keyof T>(key: K): T[K] | undefined // 如果需要用到has、delete等其他Map方法,可按照相同规则补充重载 } & Omit<Map<keyof T, T[keyof T]>, 'set' | 'get'> // 定义你的键值映射规则:key为string时value为number,key为number时value为string type MyKVRule = { string: number number: string } // 实例化 const map = new Map() as ConstrainedMap<MyKVRule> // 效果和方案1完全一致,需要新增规则时只需要修改MyKVRule即可
内容的提问来源于stack exchange,提问作者Zied Hf
相关产品推荐
相关产品推荐

