使用map创建含不同键的对象数组时遇TypeScript错误
TypeScript动态创建符合索引签名类型的对象数组报错解决办法
问题场景
我需要动态创建一个对象数组,每个对象的键可能不同,但都符合myType的索引签名定义。直接赋值数组没问题,但用map生成时TypeScript报错。极简示例如下:
type myType = { [key: string]: number; }; // 直接赋值无报错 const doesNotComplain: myType[] = [{ a: 1 }, { b: 2 }]; // 使用map生成时报错 const doesComplain: myType[] = [1, 0, 0, 0, 1, 0].map((e) => { if (e == 1) return { a: 1 }; return { b: 2 }; });
报错信息
Type '({ a: number; b?: undefined; } | { b: number; a?: undefined; })[]' is not assignable to type 'myType[]'. Type '{ a: number; b?: undefined; } | { b: number; a?: undefined; }' is not assignable to type 'myType'. Type '{ a: number; b?: undefined; }' is not assignable to type 'myType'. Property 'b' is incompatible with index signature. Type 'undefined' is not assignable to type 'number'.
已尝试的无效方案:
- 要求数组长度固定的方案不符合动态生成场景
- 将类型改为
number | undefined会允许键值为undefined,不符合需求 - 只能临时用
// @ts-ignore跳过检查,但违背TypeScript类型校验的初衷
解决方案
方案1:给map指定泛型参数
直接在map方法上声明返回类型为myType,让TypeScript跳过对回调返回值的联合类型推断,直接匹配目标类型:
const doesComplain: myType[] = [1, 0, 0, 0, 1, 0].map<myType>((e) => { if (e == 1) return { a: 1 }; return { b: 2 }; });
方案2:在回调返回值处显式断言
对每个分支的返回对象断言为myType,明确告诉TypeScript该对象符合目标类型:
const doesComplain: myType[] = [1, 0, 0, 0, 1, 0].map((e) => { if (e == 1) return { a: 1 } as myType; return { b: 2 } as myType; });
方案3:使用类型收窄工具函数
如果觉得断言不够优雅,可以封装一个简单的工具函数来做类型收窄:
const toMyType = (obj: {[key: string]: number}): myType => obj; const doesComplain: myType[] = [1, 0, 0, 0, 1, 0].map((e) => { if (e == 1) return toMyType({ a: 1 }); return toMyType({ b: 2 }); });
报错原因解释
直接赋值数组时,TypeScript会把每个对象直接匹配到myType的索引签名;但map回调中,TypeScript会分别推断两个分支的对象类型({a: number}和{b: number}),并合并为联合类型。这个联合类型中,每个对象都隐含了「未定义的键为undefined」的特性,而myType的索引签名要求所有字符串键对应的value必须是number,undefined显然不符合要求,因此触发报错。
内容的提问来源于stack exchange,提问作者Emmanuel D
相关产品推荐
相关产品推荐

