[TYPESCRIPT] Một số scripts hay được sử dụng trong typescripts (ok)
Một ví dụ sử dụng decorators
Chú ý tới lệnh
https://www.youtube.com/watch?v=cRWF9e-1DxQ
A practical guide to TypeScript decorators
May 13, 2020 5 min read
We can all agree that JavaScript is an amazing programming language that allows you to build apps on almost any platform. Although it comes with its own fair share of drawbacks, TypeScript has done a great job of covering up some gaps inherent in JavaScript. Not only does it add type safety to a dynamic language, but it also comes with some cool features that don’t exist yet in JavaScript, such as decorators.
What are decorators?
Although the definition might vary for different programming languages, the reason why decorators exist is pretty much the same across the board. In a nutshell, a decorator is a pattern in programming in which you wrap something to change its behavior.
In JavaScript, this feature is currently at stage two. It’s not yet available in browsers or Node.js, but you can test it out by using compilers like Babel. Having said that, it’s not exactly a brand new thing; several programming languages, such as Python, Java, and C#, adopted this pattern before JavaScript.
Even though JavaScript already has this feature proposed, TypeScript’s decorator feature is different in a few significant ways. Since TypeScript is a strongly typed language, you can access some additional information associated with your data types to do some cool stuff, such as runtime type-assertion and dependency injection.
Getting started
Start by creating a blank Node.js project.
Next, install TypeScript as a development dependency.
The @types/node
package contains the Node.js type definitions for TypeScript. We need this package to access some Node.js standard libraries.
Add an npm script in the package.json
file to compile your TypeScript code.
TypeScript has labeled this feature as experimental. Nonetheless, it’s stable enough to use in production. In fact, the open source community has been using it for quite a while.
To activate the feature, you’ll need to make some adjustments to your tsconfig.json
file.
Create a simple TypeScript file to test it out.
Instead of repeating this command over and over, you can simplify the compilation and execution process by using a package called ts-node
. It’s a community package that enables you to run TypeScript code directly without first compiling it.
Let’s install it as a development dependency.
Next, add a start
script to the package.json
file.
Simply run npm start
to run your code.
For reference, I have all the source code on this article published on my GitHub. You can clone it onto your computer using the command below.
Types of decorators
In TypeScript, decorators are functions that can be attached to classes and their members, such as methods and properties. Let’s look at some examples.
Class decorator
When you attach a function to a class as a decorator, you’ll receive the class constructor as the first parameter.
If you want to override the properties within the class, you can return a new class that extends its constructor and set the properties.
Now your Rocket
class will have a fuel
property with a default value of 100
.
Method decorator
Another good place to attach a decorator is the class method. Here, you’re getting three parameters in your function: target
, propertyKey
, and descriptor
.
The first parameter contains the class where this method lives, which, in this case, is the Rocket
class. The second parameter contains your method name in string format, and the last parameter is the property descriptor, a set of information that defines a property behavior. This can be used to observe, modify, or replace a method definition.
The method decorator can be very useful if you want to extend the functionality of your method, which we’ll cover later.
Property decorator
Just like the method decorator, you’ll get the target
and propertyKey
parameter. The only difference is that you don’t get the property descriptor.
There are several other places to attach your decorators in TypeScript, but that’s beyond the scope of this article. If you’re curious, you can read more about it in the TypeScript docs.
Use cases for TypeScript decorators
Now that we’ve covered what decorators are and how to use them properly, let’s take a look at some specific problems decorators can help us solve.
Calculate execution time
Let’s say you want to estimate how long it takes to run a function as a way to gauge your application performance. You can create a decorator to calculate the execution time of a method and print it on the console.
The Rocket
class has a launch
method inside of it. To measure the execution time of the launch
method, you can attach the measure
decorator.
As you can see, the measure
decorator replaces the original method with a new one that enables it to calculate the execution time of the original method and log it to the console.
To calculate the execution time, we’ll use the Performance Hooks API from the Node.js standard library.
Instantiate a new Rocket
instance and call the launch
method.
You’ll get the following result.
Decorator factory
To configure your decorators to act differently in a certain scenario, you can use a concept called decorator factory.
Decorator factory is a function that returns a decorator. This enables you to customize the behavior of your decorators by passing some parameters in the factory.
Take a look at the example below.
The changeValue
function returns a decorator that change the value of the property based on the value passed from your factory.
Now, if you bind your decorator factory to the fuel
property, the value will be 100
.
Automatic error guard
Let’s implement what we’ve learned to solve a real-world problem.
Let’s say you have a Rocket
class that has a launchToMars
method. To launch a rocket to Mars, the fuel level must be above 100.
Let’s create the decorator for it.
The minumumFuel
is a factory decorator. It takes the fuel
parameter, which indicates how much fuel is needed to launch a particular rocket.
To check the fuel condition, wrap the original method with a new method, just like in the previous use case.
Now you can plug your decorator to the launchToMars
method and set the minimum fuel level.
Now if you invoke the launchToMars
method, it won’t launch the rocket to Mars because the current fuel level is 50.
The cool thing about this decorator is that you can apply the same logic into a different method without rewriting the whole if-else statement.
Let’s say you want to make a new method to launch the rocket to the moon. To do that, the fuel level must be above 25.
Repeat the same code and change the parameter.
Now, this rocket can be launched to the moon.
This type of decorator can be very useful for authentication and authorization purposes, such as checking whether a user is allowed to access some private data or not.
Conclusion
It’s true that, in some scenarios, it’s not necessary to make your own decorators. Many TypeScript libraries/frameworks out there, such as TypeORM and Angular, already provide all the decorators you need. But it’s always worth the extra effort to understand what’s going on under the hood, and it might even inspire you to build your own TypeScript framework.
LogRocket: Debug JavaScript errors easier by understanding the context
Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.
LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!Try it for free.
Last updated