Search code examples
javascriptangulartypescriptjavascript-objects

Typescript property decorator - Need help to understand how the following happens?


I was just experimenting with Typescript property decorators. But, I could not understand the behavior of the following code :

function dec(hasRole: boolean) {
    return function (target: any, propertyName: string) {
        let val = target[propertyName];
        Object.defineProperty(target, propertyName, {
            get() { return val; },
            set(value) { val = hasRole; }
        });
    }
}

class Hey {
    age: number;

    @dec(true)
    hasRole: boolean = false;

    constructor(age: number) {
        this.age = age;
    }
}

let ob = new Hey(22);
console.log(ob);

//Actual Output:

age: 22
hasRole: true
__proto__:
  constructor: class Hey
  hasRole: true
  get hasRole: ƒ get()
  set hasRole: ƒ set(value)
  __proto__: Object

The result I expected was: 1. OwnProperty -> hasRole = false 2. Prototype property -> hasRole = true. As 'target' in decorator argument provides the constructor function for static members or prototype of the class for instance members.

Could someone explain me this functionality ?


Solution

  • In order to understand it clearly you should take a look at the transpiled version

    function dec(hasRole) {
        return function (target, propertyName) {
            let val = target[propertyName];
            Object.defineProperty(target, propertyName, {
                get() { return val; },
                set(value) { val = hasRole; }
            });
        };
    }
    class Hey {
        constructor(age) {
            this.hasRole = false;
            this.age = age;
        }
    }
    __decorate([
        dec(true)
    ], Hey.prototype, "hasRole", void 0);
    let ob = new Hey(22);
    console.log(ob);
    

    From the code above it should be clear that class is decorated first and only then a new instance is created

    It means that at the time constructor is being executed hasRole is already defined in Prototype hence assigning this.hasRole to anything doesn't have any effect: it's always assigned to hasRole parameter in decorator(which is true)