Decorators
Decorators are an experimental feature of TypeScript that allow you to add extra powers to ES2015 classes. The implementation which TypeScript uses is different from the TC39 proposal (currently in Stage 2), so using decorators is discouraged. However, if you find yourself working in a codebase that uses decorators, it could be helpful to know how they work.
Decorators are functions that we can attach to classes and their members. These decorator functions get different parts of the class as their parameters, and allow us to do something with that class (or class member). Decorators allow us to reuse logic between multiple classes without resorting to class inheritance.
Since this is an experimental feature, you need to turn on the **experimentalDecorators**
option in tsconfig.json.
There are several different kinds of decorators; we'll go over each of them.
Class Decorator
We can attach a function to a class which will be called when that class is instantiated. The function gets the class constructor as it's first parameter. We have to return a class definition. Typically we extend the class that is being decorated.
We're using the **Instantiable**
type to represent any object that can be instantiated using the **new**
keyword, including classes. By using the generic **TClass**
type to represent our class, we can maintain type safety and only allow our function to be used when decorating classes.
We can then decorate our class using **@**
followed by our function.
Suppose we wanted to pass parameters into our decorator. We can do that by creating a "decorator factory". This is a function which returns our decorator function, and it looks something like this:
Property Decorators
We can use property decorators to add metadata or logic to a class property. This is done using property descriptors, which are explained in much better detail in this MDN article.
We can use it to transform a regular property into an accessor property, with getters and setters. The first parameter is the class prototype; we'll use any to represent it. We also get the name of the property we decorated as the second parameter.
We'll create a set of functions which set the decorated property to be uppercase. We'll store the value outside of the class instance that we don't destroy our call stack with recursive calls to our setter function.
We can also use the same "function returning another function" factory pattern to create property decorator factories.
Method Decorators
Method decorators work similarly to property decorators; they are a function where the first parameter is the class prototype and the second is the method name. The third property is the property descriptor for the method which can be modified directly.