首页 > 解决方案 > 打字稿:一个类方法可以成为另一个方法的装饰器吗?

问题描述

可以像下面这样工作吗?

class A {
  private mySecretNumber = 2;

  decorate (f: (x :number) => number) {
    return (x: number) => f(this.mySecretNumber * x);
  }

  @(this.decorate)
  method (x: number) {
    return x + 1;
  }
}

我试过@this['decorate'], @A['decorate'], @A.decorate,找不到任何东西。

这是我的用例示例:https ://kutt.it/uOxVgM 。理想情况下,我只会装饰getAbc()get123()

标签: typescript

解决方案


你的问题有很多微妙之处。

第一件事是,是的,您确实可以将方法用作装饰器,但不能通过编写@this.decorate(在转译期间,this将是globalThis代替A)或@A.decoratedecorate不是静态方法,因此A.decorate不存在)。这部分问题的正确答案是@A.prototype.decorate;这将准确定位您的想法。

第二件事是,当将装饰器应用于类的方法时,装饰器的参数不是方法函数本身,而是它实际上有 3 个参数:一个目标对象(A.prototype在我们的例子中),一个字符串 (方法的名称,"method"在我们的例子中)和一个属性描述符对象。它也不会返回一个新函数,但如果不是 void,它应该返回一个新的属性描述符。所以在装饰器函数内部,你应该尝试修改目标对象,而不是尝试返回一个新函数。

把事情放在一起,一个工作的例子将是:

class A {
    private mySecretNumber = 2;

    decorate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        var f = descriptor.value;
        // Don't use arrow function here, otherwise "this"
        // will not be the current A instance.
        descriptor.value = function(x: number) {
            return f(this.mySecretNumber * x);
        };
        Object.defineProperty(target, propertyKey, descriptor);
    }

    @A.prototype.decorate
    method(x: number) {
        return x + 1;
    }
}

var a = new A();
console.log(a.method(3)); // 7

更新:

根据您的用例,我将使用以下方法。基本上,您使用静态装饰器来加载decorate可以在子类中实现的抽象方法。我修改了上面的例子,让你知道它是如何完成的。

abstract class A {
    protected abstract decorate(x: number): number;

    static decorate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        var f = descriptor.value;
        descriptor.value = function(x: number) {
            return f(this.decorate(x));
        };
        Object.defineProperty(target, propertyKey, descriptor);
    }

    @A.decorate
    method(x: number) {
        return x + 1;
    }
}

class B extends A {
    private mySecretNumber = 2;
    protected decorate(x: number) { return this.mySecretNumber * x; }
}

var b = new B();
console.log(b.method(3)); // 7

推荐阅读