Using Class Decorators in Typescript with a real example

Using Class Decorators in Typescript with a real example

The Decorators are an excellent Typescript feature; maybe you see them all over Angular and other frameworks.

It helps to write code clean and declarative, maybe you already use it every day, but do you know when to create your decorators?

I will show you how to create your decorators and even how to implement them.

What is a Decorator?

The Decorator is a function that we can hook into our code to extend with some behavior and helps us to write code abstractions that help develop code clear.

The decorator function depends on which you will decorate. That means it doesn't get the same parameters when working over a class, methods, or properties.

Where can I Use Decorators?

The decorators help in some class code areas.

  • class definition
  • properties
  • methods
  • accessors
  • parameters.

My first class decorator

Class decorators take the constructor function as a parameter, which means we can change how we initialize the class.

Let me show a simple case; we have a few entities class, everyone needs to have the id and created property, the standard solution is to create a base class.

class BaseEntity {
  readonly id: number;
  readonly created: string;
  constructor() {
    this.id = Math.random();
    this.created = new Date().toLocaleDateString();
  }
}

The Course class extends from BaseEntity class and call the constructor super().

class Course extends BaseEntity {
  constructor(public name: string) {
    super();
  }
}

let englishCourse = new Course("English");
console.log("id: " + englishCourse.id);
console.log("created: " + englishCourse.created);

Perfect, it works. But How can we solve it with decorators?

The Decorator

The decorator class is a function and gets the constructor as a parameter, including the id and created properties.

function BaseEntity(ctr: Function) {
  ctr.prototype.id = Math.random();
  ctr.prototype.created = new Date().toLocaleString("es-ES");
}

The Decorator is ready to be used in each entity without modifying its constructor or extending. He only needs to add @Entity before the class definition.

@BaseEntity
class User {
  constructor(public name: string) {}
}

@BaseEntity
class City {
  constructor(public zicode: number) {}
}

let user = new User("dany");
let ny = new City("RD");
//City and User classes has the id and created property ;)
console.log(ny.id);
console.log(user.id);

Decorator Factory

The decorator factory is a function that returns the decorator function itself; it gives the flexibility to pass parameters to the decorators.

A new property position is a number, a random number between 0 to some parameter number.

function LuckyNumber(limit: number) { 
  return function (constructor: Function) { 
    constructor.prototype.lucky = Math.floor(
      Math.random() * Math.floor(limit)
  }
}

The Decorator LuckyNumber gets a number as a parameter to set the range limit nest with the base entity.

@BaseEntity
@LuckyNumber(3)
class User {
  constructor(public name: string) {}
}

@BaseEntity
@LuckyNumber(3)
class City {
  constructor(public zicode: number) {}
}

let user = new User("dany");
let ny = new City(08930);
//the City and User has the lucky number property
console.log(ny.lucky);
console.log(user.lucky);

The decorators help to add behavior and metadata to classes and methods or properties in a declarative way.

Done

Hopefully, that will help you with how and when using Decorators in class with Typescript. If you enjoyed this post, share it!

Photo by Ferenc Almasi on Unsplash