The Decorators are a great Typescript feature, maybe you see them all over Angular and other frameworks.
It helps to write code clean and declarative, maybe you already use every day, but do you know when to create your own decorators?
I will show how to create your own decorators and even how to implement it.
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 extend code clear.
The decorator function depends on which you will decorate, that's mean it doesn't get the same parameters when it is working over a class, methods or properties.
Where can I Use Decorators?
The decorators are used in some class code areas.
- class definition
- properties
- methods
- accessors
- parameters.
My first class decorator
The decorators in classes take the constructor function as a parameter that means we can change the way how its class is initialized.
Let me show a simple case, we have a few entities class, everyone needs to have the id and created property, the normal 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, then include 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 his constructor or extend, only needs to add @Entity before 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 get a number as parameter to set the range limit, the new Decorator can be use nested with other.
@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 also methods or properties using a declarative way.
That's it!
Hopefully, that will give you a bit of help with how and when using Decorators in class with Typescript. If you enjoyed this post, share it!
Photo by Ferenc Almasi on Unsplash
Top comments (2)
так ты гонишь без определение типа в классе никаого "ny.lucky" не получится, тебе выдаст ошибку lucky нету в данном классе...
а как можно без as типизировать?
ну вот как в более продвинутых случаях, если мы, например, возвращаем из декоратора
return class extends constructor {....}
?