How To Create a Custom Typescript Decorator
If you have been using Typescript for a while then there is a good chance that you have already seen and used decorators in your code. They are the functions that are applied to classes, methods, properties, or method parameters using the @
symbol followed by the decorator function name.
What are they used for?
TypeScript decorators are a feature of TypeScript that allows you to attach metadata to classes, methods, and properties, and execute logic when the decorated element is accessed or modified. They are a good way to modify the behavior of a class or its members at runtime, without changing the implementation of the class itself.
They can be used for a wide range of tasks, such as:
- Adding additional behavior to a class or its members
- Implementing dependency injection
- Modifying third-party libraries without having to change the implementation of the library itself.
Components of a decorator
In this article, We will be creating a memoize
method decorator that will help us cache the output of our function call to better optimize our code.
Before we get to that, let's see in detail the components of a method decorator:
The decorator function takes three parameters:
target
: This is the object that the decorator is being applied to. In the case of a method decorator, it will be the prototype of the class that the method belongs to.key
: This is the name of the decorated property or method. In the case of a method decorator, it will be the name of the method.descriptor
: This is an object that contains information about the decorated property or method, such as its value and any other properties.
Let’s get started!
Now that we have a general idea of what a decorator consists of, let's start by defining our memoize
decorator. The purpose of memoize
is to cache the results of previous function calls and use the previous result for subsequent calls with the same arguments. To do that, we will be using a Map
object to store a key value map of arguments and output in memory.
Next, we will modify the value
property of the descriptor
object to wrap the original method in a new function that will return the cached value if it exists and also store the new function call results in the cache. Finally, we return the modified descriptor
object.
We are now done with our custom decorator. The next step will be to test it out!
Let’s create a class with a recursive implementation of the Fibonacci sequence algorithm and add our decorator to it.
Running this code you should see the following output on the console:
1
1
2
3
5
8
13
21
34
55
89
144
Perfect, you could also check by running the code without the memoize
decorator, then it will take a very long time to finish.
Are there any downsides?
There are a few limitations to TypeScript decorators that you should be aware of. The first thing to note is that they are not a part of the Javascript language, so you can only use them with Typescript only.
Another thing to keep in mind when creating custom decorators is to use them for relatively simple and straightforward tasks as they might not be well-suited for modifying the behavior of classes or methods in an easily understandable or predictable way.
Conclusion
Well, that’s all for this article. I hope you gained some insights about Typescript decorators and how you could potentially leverage them on your next project. You can find the full source code here. Thank you for reading!