TypeScript循环赋值类型不兼容:如何无需硬编码类型断言解决?
TypeScript 循环赋值类型不兼容问题解决
问题代码
interface InterfaceA { transfer?: string[]; deposit?: number[]; test?: boolean[]; } interface InterfaceB extends InterfaceA { moretest?: boolean[]; } type Label = ("transfer" | "deposit" | "test") const a: InterfaceA = {} const b: InterfaceB = {} const labels: Label[] = ["transfer" , "deposit" , "test"]; for (const label of labels){ a[label] = b[label] // 编译报错:Type 'string' is not assignable to type 'number' }
报错信息
Type 'string' is not assignable to type 'number'
问题根源
虽然我们明确同一个label对应a和b的属性类型必然一致,但TypeScript在循环中无法追踪单个label的具体类型——它只能识别出label是transfer | deposit | test的联合类型,因此会判定a[label]和b[label]可能出现string[]赋值给number[]这类类型不匹配的情况。
不推荐的方案
- 粗暴使用
any断言:a[label] = b[label] as any - 硬编码分支判断:
if (label == "transfer") { a[label] = b[label] } else if (label == "deposit") { a[label] = b[label] } else { a[label] = b[label] }
优雅解决方案:泛型辅助函数
通过泛型让TypeScript精准推断每个label对应的属性类型,实现类型安全的赋值:
interface InterfaceA { transfer?: string[]; deposit?: number[]; test?: boolean[]; } interface InterfaceB extends InterfaceA { moretest?: boolean[]; } // 用keyof自动推导Label类型,避免手动枚举 type Label = keyof InterfaceA; const a: InterfaceA = {} const b: InterfaceB = {} const labels: Label[] = ["transfer", "deposit", "test"]; // 泛型函数绑定具体属性键类型 const assignProp = <K extends Label>(target: InterfaceA, source: InterfaceB, key: K) => { target[key] = source[key]; }; for (const label of labels) { assignProp(a, b, label); }
原理
每次调用assignProp时,泛型K会被推断为当前循环中label的具体类型(比如第一次是"transfer"),TypeScript能明确target[key]和source[key]的类型完全匹配,因此不会触发类型报错。
另外还有一种更简洁的写法,无需额外定义函数,利用类型断言但无需硬编码属性名:
for (const label of labels) { (a[label] as InterfaceA[typeof label]) = b[label]; }
内容的提问来源于stack exchange,提问作者Alvaro Flaño Larrondo
相关产品推荐
相关产品推荐

