我有以下装饰器:
function Unique(target: any) {
let original: any = target;
let newConstructor: any = (...args: any[]) => {
let obj = new original(args);
Object.defineProperty(obj, 'unique', {
value: true,
configurable: false,
writable: false
});
return obj;
}
newConstructor.prototype = original.prototype;
return newConstructor;
}
和以下2个类:
@Unique
class Base {
public get Name(): string { return 'Base'; }
public irrelevantValue: number;
public constructor() {
this.irrelevantValue = 3;
}
}
class Child extends Base {
public get Name(): string { return 'Child'; }
public otherIrrelevantValue: number;
public constructor() {
super();
this.otherIrrelevantValue = 9;
}
}
但是,当我这样做
let obj = new Child();
console.log(obj.Name);
我得到Base
而不是Child
。只有在存在Unique装饰器的情况下,这种情况才会发生,因此我认为问题在于Unique覆盖目标原型的方式。
如何在父类上使用构造函数覆盖装饰器而不覆盖继承的属性/值/方法?
值得注意的是,在上面的示例中,调用obj.otherIrrelevantValue
将正确返回9。
答案 0 :(得分:1)
如果从构造函数返回一个对象,则该对象将成为new
返回的实例。由于您使用new
来调用基类构造函数,因此将创建基类的新实例(而不是正在创建的当前类),并且该基类实例将成为new Child
的返回值>
最安全的方法是通过扩展标准类来替换原始类,即使用标准类扩展语法:
function Unique<T extends new (...arg: any[])=> any>(target: T) {
let original: any = target;
return class extends target {
constructor(...args: any[]){
super(...args);
Object.defineProperty(this, 'unique', {
value: true,
configurable: false,
writable: false
});
}
};
}
@Unique
class Base {
public get Name(): string { return 'Base'; }
public irrelevantValue: number;
public constructor() {
this.irrelevantValue = 3;
}
}
class Child extends Base {
public get Name(): string { return 'Child'; }
public otherIrrelevantValue!: number;
public constructor() {
super();
this.otherIrrelevantValue = 9;
}
}
let obj = new Child();
console.log(obj.Name);
或使用原始语法:
function Unique<T extends new (...arg: any[])=> any>(target: T) {
let newConstructor: any = function (this: any, ...args: any[]) {
let _this = target.apply(args) || this; // replce this only if the base calss retunrs somthing (It usually will not)
Object.defineProperty(_this, 'unique', {
value: true,
configurable: false,
writable: false
});
return _this;
}
newConstructor.prototype = target.prototype;
return newConstructor;
}