Ask all your coding questions @ codequery.io

For the following examples to work please make sure you have the following specified in your tsconfig.json:

{ "compilerOptions": { "target": "ES5", "experimentalDecorators": true, "emitDecoratorMetadata": true } }

Decorators let you add information and behavior to a class, method, property, or accessor at runtime.

Class Decorator

function smithFamily (constructor:T) { return class extends constructor { lastName = "Smith" } } @smithFamily class Person { firstName: string; constructor(m: string) { this.firstName = m; } } console.log(new Person("John"));

Output:

class_1 { firstName: 'John', lastName: 'Smith' }

Notice how we've defined a decorator function familyMember that modifies the constructor function of a class to add a lastName property.

This decorator is applied anywhere we include @familyMember before a class definition.

Method Decorator

function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) { let originalMethod = descriptor.value descriptor.value = function(){ console.log("logging a statement before running function") return originalMethod.apply() } } class SomeClass { @log someMethod(): any { console.log("running someMethod") } } let myClass = new SomeClass() myClass.someMethod()

Output

logging a statement before running function running someMethod

Notice how we first define a decorator function log that we then apply to the definition of someMethod() via @log. Unlike our first example, this function takes 3 arguments:

target: The parent class (either the constructor function for a static member or prototype for instance member)

propertyKey: The name of the property (in this instance someMethod )

) descriptor: The PropertyDescriptor for the object

Using the member's PropertyDescriptor we are able to augment the original function with a log statement.

Now we can apply this logging functionality to any class method by adding @log before the definition.

Accessor Decorator

function canEnumerate(val: boolean){ return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { descriptor.enumerable = val } } class SomeClass { _x: number; _y: number; constructor(x: number, y: number){ this._x = x; this._y = y; } @canEnumerate(true) get x(){ return this._x } @canEnumerate(false) get y(){ return this._x } } let myClass = new SomeClass(1, 2) for (let key in myClass) { console.log(key + " = " + myClass[key]); }

Output

_x = 1 _y = 2 x = 1

Notice that our decorator function canEnumerate is a decorator factory. This just means our function is a wrapper function for the decorator itself.

The advantage of a wrapper function is we can pass in values to our decorator.