TypeScript父类属性复制到子类旧写法编译失败解决方案
问题根因
TypeScript 4.4及以上版本收紧了索引赋值的严格校验规则,旧写法编译失败的核心原因有两个:
Object.keys()的默认返回值类型为string[],直接用返回的通用字符串作为索引给强类型的TypeB实例赋值时,TS会判定该索引可能不存在于目标类型上,直接抛出编译错误。- 你尝试编写的
keyof遍历方案逻辑完全写反:既颠倒了A到B的赋值方向,还在循环中反复重写A对象,完全不符合需求。
可直接编译通过的实现方案
方案1:最小改动修正原有写法(类型断言适配)
完全保留之前的遍历逻辑,仅需要给遍历的属性名加一层类型断言,告诉TS该属性属于TypeA的合法属性,改动成本最低:
class TypeA { propX: number = 0; propY: number = 0; } class TypeB extends TypeA { propZ: number = 0; } let A: TypeA = {propX: 1, propY: 2}; let B: TypeB = new TypeB(); // 加类型断言修复编译错误 Object.keys(A).forEach(prop => { const key = prop as keyof TypeA; B[key] = A[key]; }); B.propZ = 3; console.log(B); // 输出 {propX: 1, propY: 2, propZ: 3}
方案2:类型安全的for...in遍历写法
不需要类型断言,通过keyof约束遍历的属性类型,额外加自有属性判断过滤原型链上的无关属性,适配Angular默认开启的最严格TS校验模式:
let key: keyof TypeA; for (key in A) { if (Object.prototype.hasOwnProperty.call(A, key)) { B[key] = A[key]; } } B.propZ = 3;
方案3:简洁的对象合并写法
如果TypeA、TypeB的属性都是基础类型、没有需要保留的实例自有方法/访问器,可以直接用Object.assign一次性完成属性复制,代码最简洁:
// 直接将A的自有可枚举属性复制到B实例 Object.assign(B, A); B.propZ = 3;
注意:如果A上存在和B自有属性重名的字段,该写法会直接覆盖B上的原有值,使用前需要确认字段无冲突。
之前keyof写法的错误点
- 赋值方向完全颠倒:代码中写的
[key]: B[key]是把B的属性值赋给A,和"A属性复制到B"的需求完全相反 - 循环中每次都重新给A赋值新对象,属于完全多余的逻辑,还会覆盖A的原始属性值
- 未做自有属性校验,如果A的原型链上存在额外可枚举属性,会被一起遍历复制,产生非预期结果
内容的提问来源于stack exchange,提问作者ruttergod
相关产品推荐
相关产品推荐

