Decorators in Typescript and Angular
Decorator is a concept in Typescript that can be used to annotate a class or it's members. Decorator also enables meta programming where one can collect as many meta data as required during run time.
If you are coming from Asp.Net background like I do then you might be aware of Action Filters. Action filters in Asp.Net MVC Framework are also example of decorators.
Decorator in Typescript is nothing but a function and I will explain more about decorator below.
Decorator Philosophy
Decorator is an Aspect Oriented Programming paradigm. Where we modularize and define cross-cutting functionalities and hence achieve a strong Separation of Concerns. cross-cutting concerns are like logging, applying transactions, validations etc. It is a good design practice to keep our business logic code separate from other infrastructure or cross-cutting related code. And decorators are great tool to separate them in independent reusable libraries.
Decorators are inspired by Decorator Design Pattern. Decorator is also used to collect metadata at run-time and hence enables meta-programming.
Why should I use Decorator
Even though Decorators
are experimental feature in Typescript. It is wisely and widely used in many JavaScript frameworks like Angular and NgRX. I believe below are the main motivation behind Decorators and you should also start thinking to use Typescript Decorator
in your code.
- Collect meta data about class or class members.
- Separate cross cutting concerns like logging
- Remove code duplicate, repetition and redundancy anti pattern from code.
In Angular Framework there are predefined decorators like Component, Directive, Input, Output, HostListener
etc. Angular has created these decorators to keep the redundant and boring task done separately by the Angular Team itself. Therefore, the consumer or Angular Framework does not need to worry about these implementations and they just focus on business logic. Like Component decorator collects the metadata about selector name, html file path, CSS path and many more information. Under the hood Component
decorator does few important tasks that is required for each component in your project, that is very repetitive work like getting HTML file applying CSS on it, Creating custom element with the selector name and rendering it on DOM. All of these tasks are not rocket science however, it is needed for every component and something can be done very easily by decorator function.
Decorator Real World Example
I want to explain decorator work by giving practical example. Many of us might have worked with personal Advocates. How advocate works ? When you assign advocate for your case then this how coordination between you and your advocate happens:
- Any call or request coming from Court for you first goes to your advocate.
- Advocate does preliminary work on your court request and then he asks you to do the work just needed for you like putting your signatures, handing over personal docs etc.
- Once you are done with your work then advocate sends the respond back court and does further required work for court request on behalf of you and be prepared for next request.
There are many specialized Advocates who are famous for their special works like marriage certificate, crime, insurance etc. These Advocates keep doing some redundant and repetitive works for their clients. So that their clients remain happy and they just do their specific needed job only. Lots of ceremonial work and preparations are done by Advocates.
I know I have given long story :) some of you might think I am Advocate? By the way I am not an advocate! However, this example comes in my mind whenever, I think about Decorators.
Decorator Function in Typescript and its Explanation
In typescript Decorator function is typically written by just simple function which receives 3 parameters like target, propertykey and descriptor
function (target: any, propertyKey: string, descriptor: PropertyDescriptor){ }
https://gist.github.com/roopkt/ff673512f854e77a7dab6231d528438a
Decorator Example in Typescript
Decorators work very similar to Advocates like I explained above. Decorators can be applied on class and it's class members only. As of now in Typescript you can not apply decorator on any function, it has to be class or its members. Decorator is a function in Typescript and while applying decorator we have to pre·pend decorator by `@` symbol. Take below example depicted in picture, LogMethod
is a decorator which you have applied on Calculator
's add
method.
Suppose we created a decorator to log before and after class method called. Then we can create `LogMethod` decorator and apply on each method of class where we desire to log. In above diagram whenever `add` method of the calculator class will be called then first `LogMethod` function will be called. `LogMethod` will first do logging before calling actual function. Then decorator will call actual function and get the result. Also decorator will log the result of execution and then will return the result. So you can see how decorator can do logging task very simply. You just need to apply @LogMethod
decorator on add
function of the Calculator
class. Here is the code for LogMethod
decorator. This is an example of method decorator.
https://gist.github.com/roopkt/91bf8284407bc9289810de61da57cf20
Here is the code how you can apply LogMethod
decorator on add
method of Calculator
Service in your Angular App
.
https://gist.github.com/roopkt/a4f5eaf7a2192ebc3009ce099809931c
Decorator Example in Angular App
As I already mentioned decorators are widely and wisely used in Angular. There are many built in decorators. Like in NgRx
Library very famous decorator is @effect
.
I already explained you how you can create method decorator
and apply either in vanilla Typescript class or it could be a service class
of Angular App. Now I will explain you how you can create and constructor decorator
that you can use in your Angular App.
Imagine you want to aromatically unsubscribe all of your RxJS
subscriptions in your component. Sometimes we forget to unsubscribe RxJS subscriptions and hence our angular app becomes very slow because of memory leak issues. Therefore, in order to help ourselves we will create custom decorator and use it on component class. There are various ways to unsubscribe RxJS subscriptions. However for the sake of understanding decorator we will try to achieve this functionality by creating our own custom constructor
. I personally love constructor decorators because, it is very powerful such that it can intercept any public method of the target class and apply decoration on it. Here is my code for autoClearSubscriptions
decorator.
https://gist.github.com/roopkt/cd1d6798d60a7253e1242e66bf4fdc95
Now its time to apply our custom decorator on our angular component. Here is the code for that.
https://gist.github.com/roopkt/6710d618ff1b0ac033c30570d37490ac
Conclusion
I did not go more deep on decorator function and its parameters passed by Typescript. Because, it will become boring to you. However, if you really think I should explain my code as well then please feel free to write in comment box. I will be happy to see your comments and I might write explanation to my code as well till than Happy Coding and Bye Bye!