如何让TypeScript接受Map中的联合类型?
问题分析:TypeScript联合类型Map赋值报错原因及解决办法
问题代码
type DataKey = string type DataValue = {type:'A',a:string} | {type:'B',b:number} type ObjType = {data: Map<DataKey,DataValue>} const obj: ObjType = {data: new Map} fpShallowMerge<ObjType>({ data: fpMapSet('b', { type: 'B', b: 55, }) })
报错信息
Type '(map: nil | Map<string, { type: "B"; b: number; }>) => Map<string, { type: "B"; b: number; }>' is not assignable to type 'Map<string, DataValue> | ((args_0: Map<string, DataValue>, args_1: "data") => Map<string, DataValue>) | undefined'. Type '(map: nil | Map<string, { type: "B"; b: number; }>) => Map<string, { type: "B"; b: number; }>' is not assignable to type '(args_0: Map<string, DataValue>, args_1: "data") => Map<string, DataValue>'. Types of parameters 'map' and 'args_0' are incompatible. Type 'Map<string, DataValue>' is not assignable to type 'Map<string, { type: "B"; b: number; }>'. Type 'DataValue' is not assignable to type '{ type: "B"; b: number; }'. Property 'b' is missing in type '{ type: "A"; a: string; }' but required in type '{ type: "B"; b: number; }'.(2322)
报错原因
核心问题出在TypeScript对Map泛型的类型兼容性检查和fpMapSet的自动类型推断逻辑:
fpMapSet('b', {type:'B', b:55})返回的函数,TypeScript默认推断它只能接收Map<string, {type:'B', b:number}>类型的参数——因为传入的值是B类型,TS认为这个Map只能存储B类型元素。- 但
fpShallowMerge要求data对应的函数参数是Map<string, DataValue>,这个Map允许同时存在A和B类型的元素。 - 当尝试把期望接收纯B类型Map的函数,赋值给需要接收混合A/B类型Map的位置时,TS会检查:
Map<string, DataValue>包含A类型元素,而A类型没有b属性,不符合Map<string, B>的元素要求,因此判定类型不兼容,抛出错误。
解决办法
1. 显式指定fpMapSet的泛型类型
直接告诉TS,这个操作针对的是DataValue类型的Map:
fpShallowMerge<ObjType>({ data: fpMapSet<DataKey, DataValue>('b', { type: 'B', b: 55, }) })
2. 调整fpMapSet的泛型定义(自定义函数场景)
让函数支持往包含联合类型的Map中添加元素,修改类型定义:
function fpMapSet<K, V>(key: K, value: V) { return <T extends V>(map: Map<K, T> | null | undefined) => { const newMap = new Map(map); newMap.set(key, value as T); return newMap; }; }
3. 类型断言(不推荐)
如果确定类型安全,可以用断言跳过检查,但会失去TS的类型保护:
fpShallowMerge<ObjType>({ data: fpMapSet('b', { type: 'B', b: 55, }) as (map: Map<DataKey, DataValue>) => Map<DataKey, DataValue> })
内容的提问来源于stack exchange,提问作者mpen
相关产品推荐
相关产品推荐

