10

I noticed that typescript 2.0 will support readonly class properties, but it isn't available yet. The reason for this post is that I want to be smart about how I write my code today so that I can transition it with minimal pain later.

I want to use a class with readonly properties this way:

let widget = new Widget(110, 220); // width, height
//...
widget.width(200); // to modify the width, I use a setter with validation
widget.width = 300; // note: I want this to be a compile time error
//...
let w = widget.width; // and later I want to get/draw the current width

...but I can't get this to work due to fn and property having the same name - so I'll switch fn name to setWidth. I'd rather not prefix all my readonly properties with _ because in the past I've found that the pain is more than just the hassle of keying the extra character. And because of TS's type checking, I don't need the visual reminder that the property is readonly (or private).

Q1: Will the above work in typescript 2 if width is a readonly property of the widget class as below?

export class widget {
    readonly width:number;  // doesn't work in TS 1.8

    setWidth(w:number) {
        this.width = w;
    }
}

In the near term, I can either make the property public so I can access directly, with the 'risk' that I might set the property directly - or I can have private properties and write getters and setters.

Q2: If I do the latter, how much slower is the getter than direct property reference? Some of my properties will be called very frequently while dragging, so speed is important.

widget.getWidth();
// vs
widget.width;

UPDATE

I recently found this posted answer and realized that TS already supports most of what I was trying to do:

export class Widget {
    private _width:number;
    set width(w) {if (w >= 0) this._width = w}
    get width() {return this._width}
}

Usage syntax is same as for public property with no accessors, which is really nifty:

let widget = new Widget(...);
let existingWidth = widget.width;
widget.width = newWidth;

I'm hoping that TS2's readonly qualifier will give me direct read access to (private) properties (not through an accessor function, so faster), and none of my usage code will need to be changed. Anyone know?

Community
  • 1
  • 1
bedouger
  • 545
  • 2
  • 5
  • 15
  • Property accessors can be 20 times slower, and the performance is very browser dependant. See the following jsPerf - https://jsperf.com/data-vs-accessor-vs-getter-setter/2 – bnieland Mar 23 '16 at 16:31
  • I ran that jsperf (the latest version of it) and the operations/sec numbers seem unrealistically high. It's telling me that Firefox on my machine runs the getter function in less than 1 nanosecond. Doesn't seem possible... unless it's automatically spreading the work over the 4 cores of my Mac - in which case it's around 4-5 nanoseconds which still seems unrealistic. – bedouger Mar 23 '16 at 17:31
  • Well, it is easy enough to write your own test. How long does it take to access the data value 100,000 time vs using a property getter? – bnieland Mar 23 '16 at 20:41
  • 1
    @bnieland it's also easy to get such a test very wrong, mind you. – Bartek Banachewicz Mar 24 '16 at 12:14
  • @bedouger, can you explain this? "I'm hoping that TS2's readonly qualifier will give me direct read access to (private) properties (not through an accessor function, so faster), and none of my usage code will need to be changed." – robyoder Jun 20 '16 at 22:31
  • My line of thinking: In ts 1.x, the closest I can get to readonly is the export class (under UPDATE above), where I can optionally do nothing in the setter. If I didn't define a getter, then I wouldn't be able to read the value outside of this class, so I define a getter. When I say let existingWidth = widget.width, it runs the getter function (which is a little slower than accessing the value directly) In ts 2.0, I think I can declare width as readonly and not define a getter or setter. When I then say let existingWidth = widget.width, it will access the value directly and not run a function – bedouger Jun 22 '16 at 00:52

1 Answers1

10

Now that I'm using TS2, I've found that readonly is not what I want because the read-only restriction applies even inside the class. So the best I can come up with is using the private modifier and writing an explicit getter method. This is unfortunate for 2 reasons: speed of the read (presumably), and the getter method name must be different than the name of the private variable.

bedouger
  • 545
  • 2
  • 5
  • 15
  • seems like there's no way to initialize the readonly values outside the constructor. C# has myThing = new Thing(){param=val,param2=val2} but I think typescript isn't there yet. – Eric Hartford Jan 15 '17 at 06:40
  • I wouldn't worry about the speed of access unless you have specific grounds for concern. As for the naming just use 'property_name' for the getter and '_property_name' for the private variable. The leading underscore for private members is a well recognised convention in most languages. – Neutrino Jul 24 '17 at 14:44
  • What about //@ts-ignore ONLY in the setter, I know it may be seen as bad practice but in this case, in my opinion, it compensates. – tru7 Jan 10 '19 at 12:49