- vừa được xem lúc

Blog#129: 🌸Understanding the Power of the Decorator Pattern in Typescript🌸

0 0 28

Người đăng: NGUYỄN ANH TUẤN

Theo Viblo Asia

The main goal of this article is to help you improve your English level. I will use Simple English to introduce to you the concepts related to software development. In terms of IT knowledge, it might have been explained better and more clearly on the internet, but remember that the main target of this article is still to LEARN ENGLISH.


Hi, I'm Tuan, a Full-stack Web Developer from Tokyo 😊. Follow my blog to not miss out on useful and interesting articles in the future.

JavaScript is a great way to make apps on almost any platform. TypeScript is a way to make JavaScript even better. It helps make sure that the code you write is correct and it adds some extra features that JavaScript doesn't have yet.

What are decorators?

Decorators are a pattern in programming that let you wrap something to change its behavior. It's not a new thing - many programming languages like Python, Java, and C# have it. JavaScript has proposed this feature, but TypeScript's decorator feature is different because it's a strongly typed language, so you can access extra information to do cool stuff like runtime type-assertion and dependency injection.

Types of decorators

Decorators are like special labels that you can put on classes and their parts, like methods and properties. Here are some examples of what they look like.

Class decorator

When you add a special feature to a class, the first thing you get is the constructor of the class.

const classDecorator = (target: Function) => { // do something with your class
} @classDecorator
class Rocket {}

If you want to change something about the class, you can make a new class that is based on the old one, and then change the parts you want to be different.

const addFuelToRocket = (target: Function) => { return class extends target { fuel = 100 }
} @addFuelToRocket
class Rocket {}

Your Rocket class now has a fuel property that starts with a value of 100.

const rocket = new Rocket()
console.log((rocket).fuel) // 100

Method decorator

When you use a decorator, you can attach it to a class method. This means that when you use the method, you will get three pieces of information: target, propertyKey, and descriptor.

const myDecorator = (target: Object, propertyKey: string, descriptor: PropertyDescriptor) => { // do something with your method
} class Rocket { @myDecorator launch() { console.log("Launching rocket in 3... 2... 1... 🚀") }
}

The Rocket class has a special way of changing how a method works. You can give it a name and some instructions about how it should work. This can help you make the method do more than it normally would.

Property decorator

The method decorator and the parameter decorator are similar in that they both give you two things: target and propertyKey. The only difference is that the parameter decorator does not give you the property descriptor.

const propertyDecorator = (target: Object, propertyKey: string) => { // do something with your property
}

If you want to learn more about decorators in TypeScript, you can look it up in the TypeScript documents.

Use cases for TypeScript decorators

Now that we know what decorators are and how to use them, let's look at how they can help us with certain tasks.

Calculate execution time

If you want to know how fast your application is running, you can create something called a decorator that will measure how long it takes for a function to run and then show you the time on the screen.

class Rocket { @measure launch() { console.log("Launching in 3... 2... 1... 🚀"); }
}

The Rocket class has a special way to start it. To figure out how long it takes to start the Rocket, you can use the measure decorator.

import { performance } from "perf_hooks"; const measure = ( target: Object, propertyKey: string, descriptor: PropertyDescriptor
) => { const originalMethod = descriptor.value; descriptor.value = function (...args) { const start = performance.now(); const result = originalMethod.apply(this, args); const finish = performance.now(); console.log(`Execution time: ${finish - start} milliseconds`); return result; }; return descriptor;
};

We are going to use something called the Performance Hooks API from the Node.js standard library to measure how long it takes to launch a Rocket. We will create a new Rocket and then call the launch method. The measure decorator will replace the original launch method with a new one that will measure how long it takes to launch the Rocket and then log the time to the console.

const rocket = new Rocket();
rocket.launch();

You will get the following result.

Launching in 3... 2... 1... 🚀
Execution time: 1.0407989993691444 milliseconds

Decorator factory

Decorator factory is a way to make your decorations do different things in different situations. It's like a factory that makes decorations, but you can give it instructions to make the decorations do different things. For example, you can tell the factory to make a decoration that looks a certain way or does something special.

const changeValue = (value) => (target: Object, propertyKey: string) => { Object.defineProperty(target, propertyKey, { value });
};

The changeValue function makes a special thing called a decorator. This decorator changes the value of something based on what you tell it to do from your factory.

class Rocket { @changeValue(100) fuel = 50
} const rocket = new Rocket()
console.log(rocket.fuel) // 100

If you connect the decorator factory to the fuel, the amount of fuel will be 100.

Automatic error guard

Let's use what we have learned to figure out how to solve a problem in the real world.

class Rocket { fuel = 50; launchToMars() { console.log("Launching to Mars in 3... 2... 1... 🚀"); }
}

If you have a special type of spaceship called a Rocket, it needs to have enough fuel to get to Mars. We can make a special thing called a decorator that will make sure the Rocket has enough fuel before it takes off.

const minimumFuel = (fuel: number) => ( target: Object, propertyKey: string, descriptor: PropertyDescriptor
) => { const originalMethod = descriptor.value; descriptor.value = function (...args) { if (this.fuel > fuel) { originalMethod.apply(this, args); } else { console.log("Not enough fuel!"); } }; return descriptor;
}; 

The minimumFuel is like a special tool that helps you check how much fuel is needed to launch a rocket. You can use it to make sure the rocket has enough fuel before it takes off.

class Rocket { fuel = 50; @minimumFuel(100) launchToMars() { console.log("Launching to Mars in 3... 2... 1... 🚀"); }
}

If you try to make the rocket go to Mars, it won't work because it doesn't have enough fuel.

const rocket = new Rocket()
rocket.launchToMars() Not enough fuel!

This means that you can use the same code to make a new method, but just change the number you are checking for. So if you want to make a new method to launch the rocket to the moon, you can use the same code but just change the number you are checking for from 25 to something else.

class Rocket { fuel = 50; @minimumFuel(100) launchToMars() { console.log("Launching to Mars in 3... 2... 1... 🚀"); } @minimumFuel(25) launchToMoon() { console.log("Launching to Moon in 3... 2... 1... 🚀") }
}

Now, this rocket can be launched to the moon.

const rocket = new Rocket()
rocket.launchToMoon() Launching to Moon in 3... 2... 1... 🚀

This type of decorator can help you decide if someone is allowed to see special information or not. It can help you make sure that only the right people can see it.

Conclusion

Sometimes you don't need to make your own decorations. There are already libraries and frameworks like TypeORM and Angular that have all the decorations you need. But it's still a good idea to understand what's happening behind the scenes. It might even give you ideas for making your own TypeScript framework.

And Finally

As always, I hope you enjoyed this article and learned something new. Thank you and see you in the next articles!

If you liked this article, please give me a like and subscribe to support me. Thank you. 😊


The main goal of this article is to help you improve your English level. I will use Simple English to introduce to you the concepts related to software development. In terms of IT knowledge, it might have been explained better and more clearly on the internet, but remember that the main target of this article is still to LEARN ENGLISH.

Ref

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 525

- vừa được xem lúc

Type annotation vs Type Inference - Typescript

Trong bài viết này, chúng ta sẽ tìm hiểu kỹ về TypeScript bằng cách tìm hiểu sự khác biệt giữa kiểu chú thích và kiểu suy luận. Tôi sẽ cho rằng bạn có một số kinh nghiệm về JavaScript và biết về các kiểu cơ bản, như chuỗi, số và boolean.

0 0 45

- vừa được xem lúc

Type Annotation và Type Inference trong TypeScript là gì?

Khi làm việc với javascript chắc hẳn các bạn đã quá quen với việc dùng biến mà không cần phải quan tâm đến kiểu dữ liệu của nó là gì phải không? Đúng là mới đầu tiếp cận với Typescript mình cũng cảm thấy nó khá là phiền vì cần phải khai báo đủ type để nó chặt chẽ hơn. Lúc đó mình còn nghĩ: " JavaScr

0 0 37

- vừa được xem lúc

Tìm hiểu TypeScript và kiến thức cơ bản

TypeScript là gì. TypeScript sử dụng tất cả các tính năng của của ECMAScript 2015 (ES6) như classes, modules.

0 0 53

- vừa được xem lúc

TypeScript - P1: Vì sao TypeScript được yêu thích đến vậy?

Trải nghiệm thực tế. Trước khi là một Web Developer, tôi là một Mobile Developer và Java là thứ mà tôi từng theo đuổi.

0 1 69

- vừa được xem lúc

4 Tính năng rất hay từ TypeScript

Xin chào các bạn hôm nay mình xin chia sẽ những tính năng rất hay của TypeScript (TS), các bạn cùng tìm hiểu nhé. Ngoài việc set Type cho biến, tham số hay function thì ví dụ khi bạn nhìn vào một tham

0 0 96