12
Vote

Compiler allows assignments to read-only properties in strict mode

description

"use strict";
class SomeClass
{
    public get someProperty():string
    {
        return "some value";
    }
}
var someInstance = new SomeClass();
someInstance.someProperty = "another value"; //Run-time error. ECMAScript 5.1 - 11.13.1
Tested with compiler version 0.8.1.0 and --target ES5

Edited: previously, I forgot to mention compiler's --target option value.

comments

RyanCavanaugh wrote Nov 26, 2012 at 4:59 PM

Luke - what do we want the behavior to be here?

jonturner wrote Mar 7, 2013 at 11:29 PM

We currently allow this because we don't have a notion of 'readonly' in the typesystem. The problem is that adding readonly values to the type system does a few things we wanted to avoid:
  • It begins to enforce a readonly vs readwrite separation, which works its way into our assignment compatibility rules, complicating them
  • It's unclear how much becomes readonly by default. For example, to member functions become readonly?
  • It's also unclear how long readonly doesn't apply for. For example, in a constructor is readonly observed? If so, how do you safely initialize?
We went down this path when designing the 'readonly' feature, but ended up backing out because of the complexity it introduced.

rb126 wrote Mar 15, 2013 at 12:29 PM

I was just trying to set readonly properties up when I hit this problem. I first tried:
    public get val(): number {return this._val;}
    private set val(v: number) {this._val = v;}
so that I could have a property that the class can set internally but the rest of the code can't: they can only read it. But TypeScript gives an error saying the visibility of getters and setters has to be the same - why on Earth is that? C# has the "{get; private set;}" syntax for a reason. It is often very handy to have a calculated property that you don't want setting, yet when using properties it's easy for the client code to try to set it accidentally and you want a compile-time error for that.

I'm going to have to end up doing something like:
    public get_val(): number {return this._val;}
    private set_val(v: number): void {this._val = v;}
which defeats the object of using properties because now all the client code has to write code that looks like function calls:
    // var v: number = my_obj.val;  // TypeScript won't let me do this...
    var v: number = my_obj.get_val();
and inside the class it's messier too:
    // this.val = v;        // TypeScript won't let me do this...
    this.set_val(v);
Any chance of simply allowing private setters alongside public getters, and generating an error if code outside the class attempts to call the private setter using property-set syntax?

dinazil wrote Apr 9 at 12:46 PM

Are there any plans to do this? I would be extremely happy if there were read-only properties.
It would make writing and using immutable classes much easier...
And while we're at it, it would be great if these read-only properties could also be part of an interface.
Thanks.

Arnavion wrote Sat at 3:19 AM

The other way around is true too. TS allows reading set-only properties.
class Foo {
    set bar(value: number) {
        console.log(value);
    }
}

var baz = new Foo();
console.log(baz.bar);
compiles without any errors. This is made worse by the fact that "use strict" allows it too.