TypeScript中如何基于keyof预定义类型自动推断Map的value类型?
解决方案
你需要对原生Map类型做扩展,通过重载get、set方法绑定单个key和对应value的类型关系,具体实现如下:
第一步:定义扩展的Map类型
// 扩展Map接口,重载get和set方法实现键值类型绑定 interface EntitiesMapInstance extends Map<keyof EntitiesMap, Array<EntitiesMap[keyof EntitiesMap]>> { get<T extends keyof EntitiesMap>(key: T): Array<EntitiesMap[T]> | undefined set<T extends keyof EntitiesMap>(key: T, value: Array<EntitiesMap[T]>): this }
第二步:替换类中属性的类型定义
将Household类中的inhabitantsMap类型替换为上面定义的EntitiesMapInstance,初始化时加类型断言即可:
class Household { inhabitantsObject: { [K in keyof EntitiesMap]?: EntitiesMap[K][] } = {} // 替换为扩展后的Map类型,初始化用as断言 inhabitantsMap: EntitiesMapInstance = new Map() as EntitiesMapInstance getInhabitantsFromObj<T extends keyof EntitiesMap>(type: T) { return this.inhabitantsObject[type] } getInhabitantsFromMap<T extends keyof EntitiesMap>(type: T) { return this.inhabitantsMap.get(type) } }
效果验证
修改完成后,返回值会自动推断为对应类型:
house.getInhabitantsFromMap('person')自动推断为Person[] | undefinedhouse.getInhabitantsFromMap('pet')自动推断为Pet[] | undefined
同时调用set方法时也会有类型校验:比如给person键赋值Pet类型的数组会直接抛出类型错误。
原错误原因说明
原生Map<K, V>的两个泛型参数是「所有允许的key的联合类型」和「所有允许的value的联合类型」,本身不支持单个key和对应value的绑定,所以你之前直接写Map<keyof EntitiesMap, EntitiesMap[K]>会因为找不到K的作用域报错,就算能编译通过,get返回值也只会是所有value的联合类型,无法按传入的key自动缩小范围。
内容的提问来源于stack exchange,提问作者Good Idea
相关产品推荐
相关产品推荐

