You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 01:15:39