PART III: Parameter decorators & Decorator factory
这部分没有前两部分内容翔实,点到为止,更多的实践,还需要自行深入学习。
In the previous post in this series we learned what are decorators and how they are implemented in TypeScript. We know how to work with class, method and property decorators.
In this post we will learn about:
The remaining type of decorator: the parameter decorator.
How to implement a decorator factory.
How to implement configurable decorators.
We are going to use the following class to showcase these concepts.
|
Parameter decorators
- As we already know, the signature of a ParameterDecorator looks as follows.
|
- We can use a parameter decorator named
logParameter
as follows:
|
- When compiled into JavaScript the
__decorate
method (which we explained in PART I) is invoked here.
|
If we compare it with the previous decorators we could assume that because the Object.defineProperty() is invoked, the method saySomething will be replaced by the value returned by the
__decorated
function (like in the method decorator). This assumption is wrong.If we examine the code snippet above, we will notice that there is a new function named
__param
.The
__param
function is generated by the TypeScript compiler and looks as follows:
|
The
__param
function returns a decorator that wraps the parameter decorator (refereed as decorator).As we can see when the parameter decorator is invoked, its return is ignored. This means that when the
__decorate
function is invoked, its return will not be used to override the saySomething method .This is the reason why parameter decorators don’t return.
The decorator wrapper in
__param
is used to store the index of the parameter in a closure. The index is just the position in the list of arguments.
|
Now we know that a parameter decorator takes 3 parameters:
The prototype of the class being decorated.
The name of the method that contains the parameter being decorated.
The index of that parameter being decorated.
Let’s implement the logProperty decorator.
|
The parameter decorator above adds a new property (metadataKey) to the class prototype. The new property is an array and contains the indices of the parameters being decorated. We can consider this new property as metadata.
A parameter decorator is not supposed to modify the behavior of a constructor, method or property. A parameter decorator should only be used to generate some sort of metadata.
Once the metadata has been created we can use another decorator to read it. For example, in the example bellow we can find and updated version of the method decorator that we created in PART II.
The original version logged in console the function name and all its arguments when it was invoked.
The new version reads the metadata to log in console only the parameters that have been decorated using the parameter decorator.
|
In the PART IV of this series we will learn a better way to work with metadata: The metadata reflection API. The bellow is just a sneak peek of what we will learn.
|
Decorator factory
The official TypeScript decorators proposal defines a decorator factory as follows:
A decorator factory is a function that can accept any number of arguments, and must return one of the types of decorator.
- We have learned how to implement and consume all the available types of decorator (class, method, property and parameter) but there is something that we can improve. Let’s consider the following code snippet:
|
- The above works but it would be better if we could just consume a decorator everywhere without having to worry about its type as follows:
|
- We can achieve this by wrapping all the decorators with a decorator factory. The decorator factory is able to identify what type of decorator is required by checking the arguments passed to the decorator:
|
Configurable decorators
- The last thing that we will learn in this post is how to allow developers to pass arguments to a decorator when it is consumed.
|
We can use a decorator factory to create configurable decorators.
|
- We can apply the same idea to the other decorator types (method, property and parameter) to make them configurable.
Conclusion
We now understand in-depth 4 out of the 4 available types of decorators, how to create a decorator factory and how to use a decorator factory to implement configurable decorators.