Member variables that are declared as readonly can be assigned with their declaration, or from the constructor. There's a certain C# familiarity with this.
Example 1
Here, the readonly member variable is assigned directly, which is useful if you know what a value is, and that it's never going to change.
class Foo {
public readonly bar: number = 123;
}
Example 2
Here, the readonly member variable is declared, and then assigned from the constructor, which is useful if you don't yet know the final value, but some constructor logic will resolve this for you.
class Foo {
public readonly bar: number;
constructor(bar: number) {
this.bar = 123 * bar / 100;
}
}
Example 3
Here the readonly member variable uses TypeScript's short-hand member variable declaration, where global member variables can be assigned from the constructor, which is useful if you want the user to input a value which will then never change. In this particular example, bar can either be set by the user, or will default to 123.
class Foo {
constructor(public readonly: bar: number = 123) {
}
}
Example 4
This is something you don't want to do, because the emitted JavaScript causes two assignments to the same variable. I'm just adding this so that future developers know they probably shouldn't do this.
class Foo {
public readonly bar: number = 123;
constructor(bar: number) {
this.bar = bar;
}
}
The emitted JavaScript will look something like this...
var Foo = (function () {
function Foo(bar) {
this.bar = 123; // :)
this.bar = bar; // :(
}
return Foo;
})();
What about immutability?
readonly is only upheld by TypeScript and it's compiler; there's no readonly in JavaScript (well, that's not entirely true, just that TypeScript doesn't emit truly readonly values). There are a couple of workarounds for this (and yes, it would be nice if TypeScript could emit these for us!)
Creating an immutable member variable
class Foo {
// TypeScript respects "readonly"
public readonly bar: number;
constructor(bar: number) {
// JavaScript respects property that isn't writable.
Object.defineProperty(this, "bar", {
value: bar,
enumerable: true,
configurable: false,
writable: false
});
}
}
Creating an immutable class
class Foo {
constructor(public readonly bar: number) {
// Nothing in the object is allowed to be reassigned.
Object.freeze(this);
}
}
readonlyclass member can be assigned to, and that's the constructor. However, direct assignments to class members at their declaration also ultimately happen in the constructor, hence why it's allowed (i.e. TypeScript doesn't differentiate between the two). If you check out the compiled JavaScript output, you'll understand why this is the case. The direct member assignments are effectively "inserted" into the top of the constructor (but after anysupercalls).