Angular组件继承中模型实例校验异常问题
Angular组件继承中
instanceof校验失败问题 我在Angular组件继承场景下遇到问题:基组件BaseRegistrationModelComponent负责注册表单通用功能,ProductRegistrationComponent继承该基组件。在ProductRegistrationComponent的submitForm方法中,校验this.model是否为Product实例时,尽管已通过基组件初始化,却始终进入else分支,输出错误信息:Error: this.model is not an instance of Product。
相关组件代码如下:
ProductRegistrationScreenComponent
export class ProductRegistrationScreenComponent { @ViewChild(ProductRegistrationComponent) productRegistration!: ProductRegistrationComponent; }
ProductRegistrationComponent
export class ProductRegistrationComponent extends BaseRegistrationModelComponent<Product>{ constructor(crudService: CrudService<Product>, configService: ProductConfigService) { super(crudService, configService); } override submitForm() { /* 测试:初始化基组件后,this.model是否为Product实例? */ if (this.model instanceof Product) { console.info('this.model is an instance of Product.'); } else{ console.error('Error: this.model is not an instance of Product.'); } super.model.purchasePrice = parseFloat(super.model.purchasePrice.toString().replace('R$ ', '').replace(',', '.')); super.crudService.create(super.model).subscribe(() => { super.model = super.createEmptyInstance(); super.loadProducts(); }); } }
BaseRegistrationModelComponent
@Injectable() export class BaseRegistrationModelComponent <T extends Persistable>{ model: T = this.createEmptyInstance(); modelList: T[] = []; registrationCompleted: boolean = false; commonUtils: any; constructor( public crudService: CrudService<T>, public configService: ConfigService ) { this.crudService.setConfigService(this.configService); this.loadProducts(); } public createEmptyInstance(): T { return {} as T; } loadProducts() { this.crudService.getAll().subscribe((products) => { this.modelList = products; }); } submitForm() { this.crudService.create(this.model).subscribe(() => { this.model = this.createEmptyInstance(); this.loadProducts(); }); } }
问题原因
核心问题出在基组件的createEmptyInstance方法:
public createEmptyInstance(): T { return {} as T; }
这里只是把空对象类型断言为T,但实际上这个空对象并不是Product类的实例——它没有Product的构造函数原型链,所以instanceof判断会失败。TypeScript的类型断言只是编译时的类型提示,不会改变运行时的对象本质。
解决方法
要让model成为真正的Product实例,需要让子类重写createEmptyInstance方法,返回Product的实例:
1. 将基组件的createEmptyInstance改为抽象方法
修改BaseRegistrationModelComponent,把createEmptyInstance定义为抽象方法,强制子类实现:
@Injectable() export abstract class BaseRegistrationModelComponent <T extends Persistable>{ model: T = this.createEmptyInstance(); modelList: T[] = []; registrationCompleted: boolean = false; commonUtils: any; constructor( public crudService: CrudService<T>, public configService: ConfigService ) { this.crudService.setConfigService(this.configService); this.loadProducts(); } // 改为抽象方法,要求子类实现 public abstract createEmptyInstance(): T; loadProducts() { this.crudService.getAll().subscribe((products) => { this.modelList = products; }); } submitForm() { this.crudService.create(this.model).subscribe(() => { this.model = this.createEmptyInstance(); this.loadProducts(); }); } }
2. 在ProductRegistrationComponent中实现createEmptyInstance
返回真正的Product实例:
export class ProductRegistrationComponent extends BaseRegistrationModelComponent<Product>{ constructor(crudService: CrudService<Product>, configService: ProductConfigService) { super(crudService, configService); } // 重写方法,返回Product实例 override createEmptyInstance(): Product { return new Product(); } override submitForm() { if (this.model instanceof Product) { console.info('this.model is an instance of Product.'); } else{ console.error('Error: this.model is not an instance of Product.'); } super.model.purchasePrice = parseFloat(super.model.purchasePrice.toString().replace('R$ ', '').replace(',', '.')); super.crudService.create(super.model).subscribe(() => { super.model = super.createEmptyInstance(); super.loadProducts(); }); } }
补充说明
- 若不想将基组件改为抽象类,也可保留基组件的
createEmptyInstance,但必须在子类中强制重写,确保返回正确的实例。 instanceof是运行时判断,依赖对象的原型链,因此必须保证对象是通过构造函数实例化出来的,而非空对象断言类型。
内容的提问来源于stack exchange,提问作者JamesB
相关产品推荐
相关产品推荐

