February 23, 2023

TypeScript - Class Decorators

The class decorator takes the constructor function as a parameter, allows us to change the way how this class is initialized.

Let's say we have a couple of classes Customer and Order. It is required that every class needs to have created property.

The normal solution is to create a base class which will have common fields and allow the childern to inherit from this.

In this example, we will use decorator to achieve this behavior, the decorator function will receive the target's constructor function as a parameter, and add the created property to its prototype.

Here is the code for decorator:

function EntityWithTimeStamp(constructorFunction: Function) {
    constructorFunction.prototype.created = new Date().toLocaleString("en-US");
    console.log("decorator called");
}

It receives constructorFunction(of the target class) as parameter, and adds created property to its prototype.

The decorator is ready to be used in each entity. We only need to add @EntityWithTimeStamp before class definition.

Here we define our classes and adds @EntityWithTimeStamp decorator.

@EntityWithTimeStamp
class Customer {
  constructor(public name: string) {
    console.log("Customer controctor called");
  }
}

@EntityWithTimeStamp
class Order {
  constructor(public amount: number) {
    console.log("Order  controctor called");
  }
}

Both of these classes have defined their own public properties received in constructor. Also they will have an additional property created which will be added by the decorator.

You can create objects of these classes as usual, and output the public properties to console:

let customer = new Customer("Idrees");
let order  = new Order(100);

console.log(order.amount);
console.log(customer.name);

Note that the decorator does not change the TypeScript type and the new property created is not known to the type system. The following lines will give you the error because compiler will not find created property in these referenced classes/types:

console.log(order.created);
console.log(customer.created);

Error message:

error TS2339: Property 'created' does not exist on type 'Customer'.
error TS2339: Property 'created' does not exist on type 'Order'.

There is a work around this issue, you can access the created property by temporarily casting the object to type any.

console.log((<any>order).created);
console.log((<any>customer).created);

Output will display the value of crearted property, which shows that decorator has added this field as the class member.

Related Post(s):

No comments:

Post a Comment