Lau*_*ass 2 typescript typescript-decorator
我想了解打字稿装饰器。
在这个例子中,为什么decorator1()在应用于类方法时需要括号,而decorator2不需要?我对 TS 装饰器的了解还不足以区分这两种类型的装饰器,所以任何建议都是值得赞赏的。
https://codesandbox.io/s/typescript-decorator-forked-v3u6q?file=/src/index.ts
function decorate1() {
console.log("decorate1(): factory evaluated");
return function (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
console.log("decorate1(): called");
};
}
function decorate2(target, key, descriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
// Call the original method
console.log("calling decorate2 function");
const result = original.apply(this, args);
console.log("decorate2 returned", result);
return result;
};
return descriptor;
}
class ExampleClass {
@decorate1()
@decorate2
method() {
return "something";
}
}
const example = new ExampleClass();
example.method();
Run Code Online (Sandbox Code Playgroud)
At the outset it's important to remember that decorators are an experimental feature in TypeScript, and that the corresponding JavaScript proposed feature has changed considerably and is in Stage 2 of the TC39 proposal process. As such, they are probably best avoided if you haven't started relying on them yet. If and when the decorators proposal reaches Stage 3, TypeScript will modify the TS feature to conform to it, which could be a breaking change.
Summary: decorators are functions that take certain arguments and return certain values; you can decorate with any expression as long as it acts as a decorator. Parentheses are not part of the decorator declaration syntax; they are part of the expression. If you write @foo then you are using foo as a decorator. If you write @bar() then you are using bar(), not bar, as a decorator. It's exactly like const baz = bar() and then decorating with @baz.
Anyway, you are talking about method decorators. A method decorator is a function that accepts three arguments: the class prototype or constructor (depending on the static-ness of the method being decorated); the method name, and the property descriptor for the method. And it either returns nothing, or a new property descriptor.
So here is a method decorator:
const decorator = (
target: any, key: PropertyKey, descriptor: PropertyDescriptor
) => {
console.log("decorator", key);
}
Run Code Online (Sandbox Code Playgroud)
You decorate a class method by putting a decorator declaration just before the method declaration. A decorator declaration looks like @ followed by a decorator expression. This can be any expression as long as it can act as a decorator; in this case, a function that conforms to the rule above:
class Foo {
@decorator
method1() { } //"decorator", "method1"
}
Run Code Online (Sandbox Code Playgroud)
You're decorating with the expression decorator. Note that there are no parentheses after decorator. If you wrote decorator() you would be calling decorator (with no arguments, which is wrong anyway) and since decorator() evaluates to undefined (it doesn't return a defined value), you'd be decorating with undefined, and undefined is not a decorator.
如果装饰器需要更多信息才能运行,从概念上讲,您希望它采用比所需三个参数更多的参数,但这是不允许的。允许的是创建一个获取额外信息并返回装饰器的函数。这是一个返回装饰器的函数:
const fnReturningDecorator = (name: string) => (
target: any, key: PropertyKey, descriptor: PropertyDescriptor
) => {
console.log("fnReturningDecorator", name, key);
}
Run Code Online (Sandbox Code Playgroud)
以下是如何使用它来装饰方法:
class Foo {
@fnReturningDecorator("hello")
method2() { } // "fnReturningDecorator", "hello", "method2"
}
Run Code Online (Sandbox Code Playgroud)
您正在用表达式进行装饰fnReturningDecorator("hello")。请注意,您必须fnReturningDecorator使用其string参数进行调用,然后使用返回的装饰器进行装饰。如果您不带参数编写fnReturningDecorator,那么您将使用一个接受单个string参数并返回一个函数的函数进行装饰,而这不是装饰器。同样,返回装饰器的函数本身并不是装饰器。
这相当于:
const hello = fnReturningDecorator("hello");
class Foo {
@hello
method2() { } // "fnReturningDecorator", "hello", "method2"
}
Run Code Online (Sandbox Code Playgroud)
所以括号没有什么特别的。括号只是函数调用,这样你就可以得到一个装饰器;它们不是装饰器语法的一部分。
同样,任何计算结果为正确装饰器的表达式都可以工作。作为最后一个示例,这是一个具有装饰器属性的对象:
const objHoldingDecorator = {
decorator: (
target: any, key: PropertyKey, descriptor: PropertyDescriptor
) => {
console.log("objHoldingDecorator", key);
}
}
Run Code Online (Sandbox Code Playgroud)
现在当我们想用装饰器装饰时,我们这样做:
class Foo {
@objHoldingDecorator.decorator
method3() { } // "objHoldingDecorator", "method3"
}
Run Code Online (Sandbox Code Playgroud)
同样,没有括号,但这次我们有一个点。装饰器是objHoldingDecorator.decorator;如果您尝试仅使用 进行装饰objHoldingDecorator,那么您将使用不可调用的对象进行装饰,而这不是装饰器。
| 归档时间: |
|
| 查看次数: |
1032 次 |
| 最近记录: |