Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript - getOwnPropertyNames() - Constructor Properties vs. Getter/Setter

I am quite new to TypeScript and there is a point I do not quite understand.

Imagine the following classes:

export class PropertyInConstructor {

  constructor(public foo: boolean) {

  }
}

export class PropertyWithGetSet {

  private _foo: boolean = false;

  get foo(): boolean {
    return this._foo;
  }

  set foo(theFoo: boolean) {
    this._foo = theFoo;
  }
}

From my understanding these two approaches both provide me a property that I can access using new PropertyInConstructor().foo or new PropertyWithGetSet().foo.

I now want to get the existing properties of such a class (without instance!) and to try it out:

console.log(Object.getOwnPropertyNames(PropertyInConstructor.prototype));
console.log(Object.getOwnPropertyNames(PropertyWithGetSet.prototype));

["constructor"]
["constructor", "foo"]

Why is it that the call where the properties are specified inside the constructor does not add the "foo" property?

Is there something missing or some other way to get those properties?

like image 726
JDC Avatar asked Sep 19 '25 20:09

JDC


1 Answers

Short answer: most properties are added to the instance dynamically at runtime. Properties with getters and setters need to be added to the prototype with Object.defineProperty.

Added at Runtime

With your first example:

export class PropertyInConstructor {
  constructor(public foo: boolean) {
  }
}

The property is only added to the instance when the constructor runs. Here is the transpiled JavaScript:

var PropertyInConstructor = /** @class */ (function () {
    function PropertyInConstructor(foo) {
        this.foo = foo;
    }
    return PropertyInConstructor;
}());

Effectively, the property foo does not exist on the class until the constructor runs.

This isn't just for constructor properties, it is for all properties that are not defined against the prototype, for example:

class PropertyInConstructor {
    public foo: boolean;
    constructor() {
        this.foo = true;
  }
}

Define Property

When you use get and set, things are different, because the property is added to the prototype:

var PropertyWithGetSet = /** @class */ (function () {
    function PropertyWithGetSet() {
        this._foo = false;
    }
    Object.defineProperty(PropertyWithGetSet.prototype, "foo", {
        get: function () {
            return this._foo;
        },
        set: function (theFoo) {
            this._foo = theFoo;
        },
        enumerable: true,
        configurable: true
    });
    return PropertyWithGetSet;
}());
like image 197
Fenton Avatar answered Sep 22 '25 12:09

Fenton