Decorators are a way of wrapping an existing piece of code with desired values and functionality to create a new modified version of it. Currently, it is supported only for a class and its components as mentioned below:
- Class itself
- Class Method
- Class Property
- Object Accessor ( Getter And Setter ) Of Class
- Parameter Of Class Method
Note: Currently, decorators are in a stage 2 proposal for JavaScript and are available as an experimental feature of TypeScript. To enable experimental support for decorators, you must enable the experimentalDecorators compiler option either on the command line or in your tsconfig.json
Syntax:
@<decorator-name>(argument) // code of component ...
Example: Let’s take an example, we have a Greeter class that has two properties firstMessage and secondMessage, which we will log in console. We will use a decorator to modify the firstMessage property by adding the name of the sender provided in the argument. See the class below:
Javascript
class Greeter { @ModifyMessage( 'gfg' ) first_message: string; second_message: string; } |
Here we have used a decorator ModifyMessage for the firstMessage property of the Greeter class. It will call a ModifyMessage function at runtime with the provided argument. It should return a function, inside this function we can play with the firstMessage property. See this function below:
Javascript
function ModifyMessage(sender: string) { return function (target: any, propertyKey: string) { // use sender, target and propertyKey arguments ... } } |
The function we returned takes two parameters:
- target: Constructor function of the class if we used decorator on the static member, or prototype of the class if we used decorator on instance member. In our case it is firstMessage which is an instance member, so the target will refer to the prototype of the Greeter class.
- propertyKey: It is the name of the property.
Let’s create a getter and setter function in our ModifyMessage function. These functions will be triggered when we want to get firstMessage or set firstMessage to a new value. See the code below:
Javascript
function ModifyMessage(sender: string) { return function (target: any, propertyKey: string) { let modifiedMessage: string; // Return modifiedMessage whenever the message is asked const getter = function () { return modifiedMessage; }; // Set the modifiedMessage value const setter = function () { modifiedMessage = `Hello from ${sender}!`; }; } } |
Finally, we will use the Object.defineProperty function. It is used to add a given property to an object. It takes three parameters:
- Instance of object: The object for which we want to add property. In our case, the Greeter Class instance is stored in the target variable.
- propertyName: The name of the property
- Configuration Object: It is an object with specifications of property. In our case, we will add the getter and setter function as the specification.
We will use this function to overwrite existing firstMessage property with our modifiedMessage. See the code below:
Javascript
function ModifyMessage(sender: string) return function (target: any, propertyKey: string) { let modifiedMessage: string; // Return modifiedMessage whenever the message is asked const getter = function () { return modifiedMessage; }; // Set the modifiedMessage value const setter = function () { modifiedMessage = `Hello from ${sender}!`; }; // Overwrite the original message with // modifiedMessage we just created Object.defineProperty(target, propertyKey, { get: getter, set: setter }); } } |
Now we are ready to use the decorator. See the full code below:
Javascript
function ModifyMessage(sender: string) { return function (target: any, propertyKey: string) { let modifiedMessage : string; // Return modifiedMessage whenever the message is asked const getter = function () { return modifiedMessage; }; // Set the modifiedMessage value const setter = function () { modifiedMessage = `Hello from ${sender}!`; }; // Overwrite the original message with // modifiedMessage we just created Object.defineProperty(target, propertyKey, { get: getter, set: setter }); } } class Greeter { // Modify message property using decorator @ModifyMessage( "gfg" ) firstMessage: string; secondMessage: string; constructor() { this .firstMessage = "Hi there!" ; this .secondMessage = "Hi there!" ; } greet() { console.log(`first message: ${ this .firstMessage}`); console.log(`second message: ${ this .secondMessage}`); } } let myGreeter = new Greeter(); myGreeter.greet(); |
Output:
first message: Hello from gfg! second message: Hi there!
Conclusion: Hence, we saw that we can use decorators on the property of classes and manipulate it. Decorators help us to create more readable and flexible code.