Search code examples
javascripttypescriptgetter-setter

TypeScript: get/set, referring to itself and underlying values


How does this particular getter/setter in TypeScript work:

export class MyClass {

  get prop() {
    return this.prop;
  }

  set prop(val: string) {
    this.prop = val;
  }

}

The getter and setter both refer to this.prop, but they both also define this.prop. So What is the actual underlying value it's pointing to?

In the translated piece of code, the piece of ES2015 code generated is:

var MyClass = /** @class */ (function () {
    function MyClass() {
    }
    Object.defineProperty(MyClass.prototype, "prop", {
        get: function () {
            return this.prop;
        },
        set: function (val) {
            this.prop = val;
        },
        enumerable: true,
        configurable: true
    });
    return MyClass;
}());

If I change the getter/setter to refer to a local variable, like so:

export class MyClass {

  private _prop;

  get prop() {
    return this._prop;
  }

  set prop(val: string) {
    this._prop = val;
  }

}

It generates this:

Object.defineProperty(exports, "__esModule", { value: true });
var MyClass = /** @class */ (function () {
    function MyClass() {
    }
    Object.defineProperty(MyClass.prototype, "prop", {
        get: function () {
            return this._prop;
        },
        set: function (val) {
            this._prop = val;
        },
        enumerable: true,
        configurable: true
    });
    return MyClass;
}());

Expecting to see var _prop defined somewhere, it is nowhere to be seen (other than returning the value, and setting it)! Am I missing a trick? Or is it implicitly defined?


Solution

  • This is the property accessor syntax in ES2015/Typescript.

    The getter defined with get defines how to retrieve the property value and will be invoked when the property value is required (ex: console.log(obj.prop); will invoke the getter).

    The setter defined with set defines how to save the property value on the object and will be invoked when the value of the property is assigned (ex: this.prop = "Test")

    You can read more about this here

    Moving on to your examples, the first one is a logic error and will cause a stack overflow exception since inside your getter, you use the same property, hence invoking the getter again, and the same for the setter. Much like this is valid syntactically but will not work:

    export class MyClass {      
        method(){
            this.method();
        }
    }
    

    The second example defines a private field but does not initialize it. Since there is no initializations there is no need to emit any code to define the _prop field, it will be created when it is first assigned in javascript. If you would have initialized the field, it would have shown up in the constructor:

    export class MyClass {
        private _prop = "";
    }
    

    would have generated :

    var MyClass = /** @class */ (function () {
        function MyClass() {
            this._prop = "";
        }
    }