子类实例b的prop3为何未定义?能否从父类直接赋值该属性?
为什么B实例的prop3是undefined?解决方案详解
原因分析
问题出在TypeScript对类实例属性的编译逻辑上:
- 当你在子类
B中声明prop3?:any时,TypeScript会在编译后的JavaScript代码里,自动在super()调用之后添加一行this.prop3 = undefined,用来初始化这个实例属性。 - 你的父类
A构造函数里用Object.assign(this, o)已经把传入的prop3:'3'赋值给了实例,但子类构造函数执行super()后,立刻执行了this.prop3 = undefined,直接覆盖了之前的值,所以最终prop3变成了undefined。
你可以查看编译后的JS代码,核心逻辑是这样的:
class A { constructor(o) { Object.assign(this, o); } } class B extends A { constructor(o) { super(o); // 这里已经把prop3设为'3' this.prop3 = undefined; // TypeScript自动生成的代码,覆盖了之前的赋值 } }
解决方案
你不需要必须在子类里额外赋值,有几种方法可以让父类直接完成prop3的赋值:
1. 用接口代替子类的属性声明
如果只是为了TypeScript的类型检查,不需要在子类里显式声明prop3,可以定义一个接口让B实现,这样编译后的代码不会生成this.prop3 = undefined的语句:
interface BInstance extends A { prop3?: any; } class A { prop1?: any; prop2?: any; constructor(o: any) { Object.assign(this, o); } } class B extends A implements BInstance { constructor(o: any) { super(o); } } let b = new B({ prop1: '1', prop2: '2', prop3: '3', prop4: '4' }); console.log(b.prop3); // 输出'3'
2. 子类构造函数中重新合并传入对象
在super()调用后,再次用Object.assign合并传入的对象,覆盖TypeScript自动生成的undefined:
class B extends A { prop3?: any; constructor(o: any) { super(o); Object.assign(this, o); // 重新合并,恢复prop3的值 } }
3. 用类型断言约束实例类型
如果不需要在类里声明prop3,可以直接用类型断言来告诉TypeScript实例包含prop3:
class A { prop1?: any; prop2?: any; constructor(o: any) { Object.assign(this, o); } } class B extends A { constructor(o: any) { super(o); } } // 用类型断言指定实例类型 let b = new B({ prop1: '1', prop2: '2', prop3: '3', prop4: '4' }) as A & { prop3?: any }; console.log(b.prop3); // 输出'3'
内容的提问来源于stack exchange,提问作者joe malik
相关产品推荐
相关产品推荐

