What is decorator?
A decorator is a way to implement instructions that need to be executed repeatedly before a function is executed, as a separate function, and then easily call it with a single line of code.
Generally, it is called by adding @Decorator
before it. It can be applied to classes, functions, variables, and even function parameters, but you should be careful because each has different parameters.
Below, we will explore the types of decorators. (The code is written in TypeScript.)
Class Decorator
Written above the class name. Generally, the decorator being called has no parameters, and only the function name is entered.
A class decorator function calls the constructor as an argument and can access the constructor and functions of that class. However, it cannot access variables declared in the class.
If you want to adjust the change of the class from the outside by putting parameters in the decorator, there is a way to put a factory in the front end. In other words, it is a method of writing a factory that receives the decorator instead and this factory calls the actual class decorator function.
@testFactory(false)
export class Car {
name: string;
price: number;
color: string;
constructor(name?: string, price?: number, color?: string) {
this.name = name ? name : '';
this.price = price ? price : 0;
this.color = color ? color : 'white';
}
}
function setDeaultValue(constructorFn: any) {
return <any>class extends constructorFn{
name = 'SM6';
price = 10000;
color = 'black';
}
}
function testFactory(setDefault: boolean) {
return setDefault ? setDeaultValue : null;
}
In the example above, it is determined whether to specify a value when creating a class depending on the parameter value of test01Factory
.
If the value is true
, the class has the values name = 'SM6', price = 10000, color = 'black'
as soon as it is called.
If the value is false
, the class has the values name = '', price = 0, color = 'white'
when it is created.
Method Decorator
Written above the function name. A method decorator function can have three arguments, in the following order:
target
: The prototype of the class. It can access all functions of the class (including the constructor).propName
: The key value of the corresponding method. The function name of the function with the decorator is entered instring
format.description
: Has the function’s functionality.
The example below is an example of preventing access to a function using a method decorator.
class Person {
constructor() {
console.log('new Person()');
}
test01() {
console.log('test01');
}
@editable(true)
test02() {
console.log('test02');
}
}
function editable(isEditable: boolean) {
return (target: any, propName: string, description: PropertyDescriptor) => {
description.writable = isEditable;
}
target
is the same as the argument value of the class decorator.
In the case of propName
, it has test02
to which the editable
decorator is applied.
And the description has three functions, each of which is as follows:
writable
: Whether modification is possible. Iffalse
, you cannot modify the parameter value when calling the function.enumerable
: Whether it is an enumeration type. Iffalse
, you cannot see the value when callingObject.keys()
.configurable
: Whether to applywritable
andenumerable
. Iffalse
, both cannot be applied arbitrarily.value
: value (functional)
Note that value
has the value of the function in the form of a function.
Parameter Decorator
You can also set decorators for each parameter of a function. In this case, it can also have three arguments, in the following order:
target
: The prototype of the class. It can access all functions of the class (including the constructor).methodName
: The key value of the function including the parameter. The function name of the parameter with the decorator is entered instring
format.paramIndex
: Refers to the calling order of the parameters, and has a value of 0 when called first.
function printInfo(target: any, methodName: string, paramIndex: number) {
console.log('target', target);
console.log('methodName', methodName);
console.log('paramIndex', paramIndex);
}
class Person {
private _name: string;
private _age: number;
constructor(name: string, age: number) {
this._name = name;
this._age = age;
}
test(@printInfo message: string) {
console.log('message');
}
}
In the example above, methodName
has test
and paramIndex
has a value of 0
.
Interestingly, you can also put a decorator on the parameters of the constructor. For example, if you put a decorator on age
in the example above, it is like the example below.
function printInfo(target: any, methodName: string, paramIndex: number) {
console.log('target', target);
console.log('methodName', methodName);
console.log('paramIndex', paramIndex);
}
class Person {
private _name: string;
private _age: number;
constructor(name: string, @printInfo age: number) {
this._name = name;
this._age = age;
}
test(message: string) {
console.log('message');
}
}
The result is as follows:
methodName: undefined
paramIndex: 1
In other words, even though it was called in the constructor, the function name has an undefined
value and the calling order is second.
Use of Parameter Decorator
In the example, you can see that the parameter decorator has no return value. So how can the parameter decorator be used?
To use this, you must explicitly access reflect-metadata
.
Through this, you can modify the value of the parameter.
If you want to import refrect-metadata
, you must add emitDecoratorMetadata
in the options of tsconfig.json
.
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
This will not be covered in detail here, so please refer to the related site.
Variable Decorator
Finally, you can put a decorator on a variable, which can have two arguments.
target
: The prototype of the class. It can access all functions of the class (including the constructor).propName
: The key value of the corresponding variable. The variable name of the variable with the decorator is entered instring
format.
The variable decorator can return a PropertyDescriptor
type, which is the same as the description of the method decorator, as a return value.
The example below is a method of determining whether to make a variable readonly
depending on the decorator’s parameter.
function writable(isWritable: boolean) {
return function(target:any, propName: string): any {
return {
writable: isWritable
}
}
}
class Person {
@writable(true)
name: string = 'Mark';
constructor() {
console.log('new Person()');
}
}
댓글남기기