Class decorator parameters

The examples we have seen so far are all class decorators. Remember that a decorator function will automatically be called by the JavaScript runtime when the class is declared. Our decorator functions up until this point have all been defined to accept a single parameter named constructor, which is of type Function. The JavaScript runtime will populate this constructor parameter automatically for us. Let's delve into this parameter in a little more detail.

Class decorators will be invoked with the constructor function of the class that has been decorated. As an example of this, consider the following code:

function classConstructorDec(constructor: Function) { 
    console.log(`constructor : ${constructor}`); 
} 
 
@classConstructorDec 
class ClassWithConstructor { 
     
} 

Here, we start with a decorator function named classConstructorDec that accepts a single argument named constructor of type Function. The first line of this function then simply prints out the value of the constructor argument. We are then applying this decorator to a class named ClassWithConstructor. The output of this code is as follows:

constructor : function ClassWithConstructor() {
    }

This output therefore shows us that our decorator function is being called with the full definition of the constructor function of the class that it is decorating.

Let's then update this decorator, as follows:

function classConstructorDec(constructor: Function) { 
    console.log(`constructor : ${constructor}`); 
    console.log(`constructor.name : ${(<any>constructor).name}`); 
    constructor.prototype.testProperty = "testProperty_value"; 
}

Here, we have updated our classConstructorDec decorator with two new lines of code. The first new line prints the name property of the constructor function to the console. Note how we have had to cast the constructor parameter to a type of any in order to successfully access the name property. This is necessary, as the name property of a function is only available from ECMAScript 6, and is only partially available in earlier browsers.

The last line of this decorator function is actually modifying the class prototype, and adding a property named testProperty (with the value testProperty_value) to the class definition itself. This is an example of how decorators can be used to modify a class definition. We can then access this class property, as follows:

let classConstrInstance = new ClassWithConstructor(); 
console.log(`classConstrInstance.testProperty : `  
    + `${(<any>classConstrInstance).testProperty}`); 

Here, we are creating an instance of the ClassWithConstructor class, named classConstrInstance. We are then logging the value of the testProperty property of this class to the console. Note how we need to cast the type of classConstrInstance variable to any in order to access the testProperty property. This is because we have not defined the testProperty property on the class definition itself, but are injecting this property through the decorator. The output of this code would be as follows:

constructor : function ClassWithConstructor() {
    }
constructor.name : ClassWithConstructor
classConstrInstance.testProperty : testProperty_value

This output shows us that we can use the name property of the class constructor to find the name of the class itself. We can also inject a class property, named testProperty, into the class definition. As can be seen by the output, the value of this testProperty property is testProperty_value, which is being set within the decorator function.