Static property decorators

Property decorators can also be applied to static class properties. There is no difference in calling syntax in our code—they are the same as normal property decorators. However, the actual arguments that are passed in at runtime are slightly different. Given our earlier definition of the property decorator propertyDec, consider what happens when this decorator is applied to a static class property, as follows:

class StaticClassWithPropertyDec { 
    @propertyDec 
    static name: string; 
} 

The output of the various console.log functions in our decorator is as follows:

target : function StaticClassWithPropertyDec() {
    }
target.constructor : function Function() { [native code] }
target.constructor.name : Function
propertyKey : name

Note here that the target argument (as printed in the first line of output) is not a class prototype (as seen before), but an actual constructor function. The definition of this target.constructor is then simply a function, named Function. The propertyKey remains the same, that is, name.

This means that we need to be a little careful about what is being passed in as the first argument to our property decorator. When the class property being decorated is marked as static, then the target argument will be the class constructor itself. When the class property is not static, the target argument will be the class prototype.

Let's modify our property decorator to correctly identify the name of the class in both of these cases, as follows:

function propertyDec(target: any, propertyKey : string) { 
    if(typeof(target) === 'function') { 
        console.log(`class name : ${target.name}`); 
    } else { 
        console.log(`class name : ${target.constructor.name}`);     
    } 
     
    console.log(`propertyKey : ${propertyKey}`); 
}

Here, we start by checking the nature of the target argument. If the typeof(target) call returns function, then we know that the target argument is the class constructor, and can then identify the class name through target.name. If the typeof(target) call does not return function, then we know that the target argument is an object prototype, and that you need to identify the class name through the target.constructor.name property. The output of this code is as follows:

class name : ClassWithPropertyDec
propertyKey : name
class name : StaticClassWithPropertyDec
propertyKey : name

Our property decorator is correctly identifying the name of the class, whether it is used on a normal class property, or a static class property.