Typescript:一个类方法可以是另一个方法的装饰器吗?
你能做一些像下面这样的工作吗Typescript:一个类方法可以是另一个方法的装饰器吗?,typescript,Typescript,你能做一些像下面这样的工作吗 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['decoration'
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['decoration'],
@A['decoration']
,@A.decoration
,但什么也找不到
下面是我的用例示例:。理想情况下,我只需要修饰一下
getAbc()
和get123()
你的问题有很多微妙之处
第一件事是,是的,你确实可以使用一个方法作为装饰器,但不是通过编写@this.decoration
(在传输过程中,这个将是全局,而不是a
)或@a.decoration
(装饰不是一个静态方法,因此a.decoration
不存在)。这部分问题的正确答案是@A.prototype.decoration
;这将准确定位您的想法
第二件事是,当对类的方法应用decorator时,decorator的参数不是方法函数本身,而是它实际上有3个参数:一个目标对象(在本例中是a.prototype
),一个字符串(方法的名称,在本例中是“method”
),和属性描述符对象。它也不会返回一个新函数,但如果不是void,它应该返回一个新的属性描述符。因此,在decorator函数中,您应该尝试修改目标对象,而不是尝试返回新函数
综合起来,一个有效的例子是:
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
更新:
基于您的用例,我将使用以下方法。基本上,您可以使用静态装饰器来加载抽象的decoration
方法,该方法可以在子类中实现。我对上面的例子进行了修改,让您了解如何做到这一点
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
您可以通过使用类型约束实现装饰器来实现这一点,该类型约束将装饰器的适用性限制在实现mySecretNumber
属性的类上。这将修复Mu Tsun Tsai提出的范围界定问题的语法和语义
以下是我想要的:
class A {
mySecretNumber = 2;
@decorate
method(x: number) {
return x + 1;
}
}
function decorate<T extends { mySecretNumber: number }, K extends keyof T>(
target: T, key: K,
descriptor: T[K] extends (n: number) => number ? TypedPropertyDescriptor<(n: number) => number> : never
) {
const f = descriptor.value;
if (f) {
descriptor.value = function (this: T, x: number) {
return f(this.mySecretNumber * x);
};
}
return descriptor;
}
A类{
mySecretNumber=2;
@装饰
方法(x:编号){
返回x+1;
}
}
功能装饰(
目标:T,键:K,
描述符:T[K]扩展(n:number)=>number?类型属性描述符number>:从不
) {
常数f=描述符值;
如果(f){
descriptor.value=function(this:T,x:number){
返回f(this.mySecretNumber*x);
};
}
返回描述符;
}
这可以确保修饰类具有类型为number
的mySecretNumber
属性,将该成员绑定到所需的This
,并且作为奖励,可以确保修饰方法具有正确的签名。我删除了我的答案,因为创建该类的实例对您有利(我建议的方法)表示decorator将有权访问这个
实例,但事实证明它没有。对于“方法decorator”来说,这似乎是最好的选择它是静态的,因为它将无法访问this
。是的,我自己也会使用静态装饰器。老实说,非静态装饰器通常没有什么意义,但弄清楚它是否可以完成仍然很有趣。我的用例是我有一个抽象类,其中装饰()
是抽象的,method()
的定义如示例中所示。在我的具体类中,我只需要实现decoration()
。但是在TS中你不能有抽象的静态方法,有没有其他“更干净”的方法来实现这一点的想法?好的,那么在你的抽象类中有一个具体的方法()
,您想在子类中对其进行修饰,对每个子类采用不同的方式?我认为您描述的结构无法达到您想要的效果,因为这种修饰不会简单地通过实现修饰()自动应用于子类
method;您仍然需要在子类中写下method()
上方的修饰,这样您就不会真正使用任何代码,因此在抽象类中也不需要decoration()
。我相信您根本不需要使用修饰,您应该重写method()子类中的
(需要时在新函数中调用super.method()
)。您能更具体地解释一下您的用例吗?看起来您试图通过在类中定义decorator来保留封装,但实际上,您的私有成员不是私有的,并且有更简单的解决方案允许它是私有的private@AluanHaddad不过,使用通用装饰器有一个缺点:TypeSc在你的例子中,如果你设置method()
若要保护,则会发生错误。@Mu TsunTsai这是真的,但我不认为这是一个缺点,因为可见性修饰符在TypeScript中是空的,将被提供真正私有成员的未来版本的ECMAScript所取代。如果您想要封装,您需要闭包,而在JavaScript和继续使用TypeScript