Daniel
Daniel

Reputation: 1026

Why can I set the value of a getter property in Typescript?

Having a class with a getter only property like this:

class Person {
  sureName: string = "";
  lastName: string = "";
  get name() {
    return `${this.sureName} ${this.lastName}`;
  }
}

I like the compact C# way of initializing things (e.g. string[] array = { "a1", "b1", "c1" }; which is also possible in Typescript. But using this short typed syntax, I'm forced to set name property:

let p: Person = {
  name: "xyz",
  sureName: "a",
  lastName: "b"
};
console.log(p); // { name: 'xyz', sureName: 'a', lastName: 'b' }

The getter modifier seems being completely ignored! Why does this strange behavior occur? This is not the case when using new operator:

let p1 = new Person();
p1.name = "Peter"; // error TS2540: Cannot assign to 'name' because it is a constant or a read-only property.

Here the getter is correctly validated from a OOP view. But compared to the first one, I don't really like the new operator: I have no intellisense on setting all required fields and I always have to type the object name as prefix (p1.xyz) which is annoying when having to set multiple propertys on well-named objects.

But for having clean OOP, I'm forced to use the new syntax. Or stop using the C# like getter/setter, and use methods like getName().

Upvotes: 1

Views: 1967

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250366

The getter is not ignored, it exists if you create an instance of the class. Creating an instance of Person means using the new operator (ie. new Person()). You can test the fact that you are not actually creating a Person by using the instanceof operator

let p: Person = {
  name: "xyz",
  sureName: "a",
  lastName: "b"
};
console.log(p instanceof Person); // will be false

What you are doing is creating an object literal (not an instance of Person) which has the same shape as Person. And since it has to have the same shape (ie the same public members) it must also have the name property. Typescript uses structural typing so this is allowed. See this answer for more details.

If you want to create a new Person and use the objet literal syntax for specifying field values, you can create a constructor with a Partial<Person> argument:

 class Person {
    constructor(value: Partial<Person>) {
        Object.assign(this, value);
    }
    sureName: string = "";
    lastName: string = "";
    get name() {
        return `${this.sureName} ${this.lastName}`;
    }
}

var p = new Person({
    sureName: "a",
    lastName: "b"
})

Upvotes: 3

Related Questions