打字稿装饰器覆盖属性

时间:2018-07-06 11:15:04

标签: typescript

我有以下装饰器:

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。

1 个答案:

答案 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;
}