How to use property decorators in typescript?


Decorators in TypeScript have programmatic access to the class definition process.

Remember that a class description lists a class's properties, specified methods, and structure. The class instance is given access to these properties and methods when created. However, before a class instance is created, decorators allow us to add code to the definition of a class. They are equivalent to C# attributes or Java annotations.

A decorator is a function that has a particular set of parameters. The JavaScript runtime automatically fills out these parameters, which give information about the class, method, or property to which the decorator has been applied. The type and number of the arguments determine where a decorator can be used.

Decorators are an experimental feature of the TypeScript compiler that is supported starting with ES5. To use decorators, a compile option must be enabled in the tsconfig.json file. The option's name is ExperimentalDecorators, and it needs to be set to true.

Decorators allow modification by enclosing an existing code with the proper functionality and values. Only one class and its parts are supported at the moment −

  • The class itself
  • Class Method
  • Class Property
  • Object Accessor (Getter and Setter) Of Class
  • Class Method Parameter

We will focus on only the Class property.

Property Decorators in TypeScript

Just before a property declaration, a Property Decorator is declared. A declaration file or ambient context cannot utilize a property decorator (such as in a declare class). Instead, a function called the property decorator is used to decorate the property declaration in our classes.

With this knowledge, we can do amusing and interesting things like change the default definition or modify our object instance by adding new properties or changing data. It receives the class's constructor function and the property's name as parameters.

Using Property Decorators

The following two parameters will be passed to the property decorator expression when it is called as a function at runtime −

  • The class prototype for an instance member or the class constructor method for a static member.
  • The member's name.

Syntax

Users can follow the below syntax to create a property decorator in TypeScript

//syntax to create decorator
Class Class_Name{
   @Decorator_Name(argument)
   // Code of Components 
}

As we can see in the syntax above, we will create the decorator’s name and argument values inside a class.

Example

First, we are creating a class named “Person.” This class has two properties, username, and greet, which we will log into the console. We will use a decorator to modify the username property by adding the name of the sender provided in the argument. See the class below −

class Person {
	@UpdatedMessage("ABC")
	username: string;
	greet: string;
}

For the username property of the Person class, we have used the decorator UpdatedMessage in this instance. With the supplied argument, it will runtime call a UpdatedMessage function. It ought to produce a function to manipulate the username property. Two parameters are required by the function we returned. The getter and setter functions will be triggered when we want to get a username or set the username to a new value.

The Object.defineProperty function will then be used. It is used to give an item a particular property.

There are three requirements −

  • The object's instance − The object to which the property will be added. In our scenario, the target variable contains an instance of the Greeter Class.

  • propertyName − The property's name.

  • Configuration Object − It is an item with defined properties. We'll add the getter and setter functions as the specification in our example.

This function will replace the current username property with the updatedMessage. Now we will combine all the steps, and the decorator is ready to use. See the following code −

function UpdatedMessage(sender: string) {
   return function (target: any, propertyKey: string){
      let updatedmessage: string
      // Return modifiedMessage whenever the message is asked
      const getter = function () {
         return updatedmessage
      }
      // Set the modifiedMessage value
      const setter = function () {
         updatedmessage = `Hi ${sender}!`
      }

      // Overwrite the original message with modifiedMessage we just created
      Object.defineProperty(target, propertyKey, {
         get: getter,
         set: setter,
      })
   }
}

class Person {
   // Modify message property using decorator
   @UpdatedMessage('ABC')
   username: string
   greet: string
   constructor() {
      this.username = 'Hi there!'
      this.greet = 'Welcome to tutorialsPoint'
   }

   message() {
      console.log(`${this.username}`)
      console.log(`${this.greet}`)
   }
}
let Greetings = new Person()
Greetings.message()

On compiling, it will generate the following JavaScript code −

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
   var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
   if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
   else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
   return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function UpdatedMessage(sender) {
   return function (target, propertyKey) {
      var updatedmessage;
      // Return modifiedMessage whenever the message is asked
      var getter = function () {
         return updatedmessage;
      };
      // Set the modifiedMessage value
      var setter = function () {
         updatedmessage = "Hi " + sender + "!";
      };
      // Overwrite the original message with modifiedMessage we just created
      Object.defineProperty(target, propertyKey, {
         get: getter,
         set: setter
      });
   };
}
var Person = /** @class */ (function () {
   function Person() {
      this.username = 'Hi there!';
      this.greet = 'Welcome to tutorialsPoint';
   }
   Person.prototype.message = function () {
      console.log("" + this.username);
      console.log("" + this.greet);
   };
   __decorate([
      UpdatedMessage('ABC')
   ], Person.prototype, "username");
   return Person;
}());
var Greetings = new Person();
Greetings.message(); 

Output

The above code will produce the following output −

Hi ABC!
Welcome to tutorialsPoint

Hence, we saw that we could use decorators on the property of classes and manipulate it. Decorators help us to create more readable and flexible code.

Updated on: 19-Dec-2022

2K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements