Final keyword in typescript?
It will be available since 1.4, you can check the Announcing TypeScript 1.4 article, "Let/Const" support section:
"TypeScript now supports using ‘let’ and ‘const’ in addition to ‘var’. These currently require the ES6 output mode, but we’re are investigating relaxing this restriction in future versions."
Const should be implemented according to the article.
You can get TypeScript 1.4 here.
Update 1
Of course, "const is not the same as final". The question was "Is there any way to make a variable available to be assigned only once?". So, according this documentation:
Const declarations must have an initializer, unless in ambient context
It is an error to write to a Const
const c = 0;
console.log(c); // OK: 0
c = 2; // Error
c++; // Error
{
const c2 = 0;
var c2 = 0; // not a redeclaration, as the var is hoisted out, but still a write to c2
}
And, for now (Nov, 2015) "const" seems to me the only way, given by typescript out-of-the-box, to accomplish the above task.
For those, who downvoted - if you have another answer, please, share it in this thread with comunity.
Update 2: readonly
The readonly modifier (thanks to @basarat) has been introduced in Typescript 2.0. You can initialize them at the point of declaration or in the constructor.
You can even declare a class property as readonly. You can initialize them at the point of declaration or in the constructor as shown below:
class Foo { readonly bar = 1; // OK readonly baz: string; constructor() { this.baz = "hello"; // OK } }
But as said @RReverser in this thread:
As usual with all the fresh stuff, you need to use npm i typescript@next to get the latest compiler with experimental features included.
You could use set/get to achieve the result.
class Test {
constructor(public a: number, private _b: number) {}
get b(): number {
return this._b;
}
}
var test = new Test(2, 1);
test.a = 5 //OK
test.b = 2 //Error
test.b
cannot be set because it doesn't have a setter.
TS compiler will not warn you about it, but the browser will throw an error.
You could use a method decorator and set the writable property of the descriptor object to false.
function final(target: Object, key: string | symbol, descriptor: PropertyDescriptor) {
descriptor.writable = false;
}
Then use the decorator in the parent class that contains the final method.
class Parent {
@final
speak() {
console.log('Parent speaking');
}
}
If you now extend the Parent class and try to overwrite it's speak
method you will get an error:
Error: "speak" is read-only
class Child extends Parent {
// Error: "speak" is read-only
speak() {
console.log('Child speaking');
}
}
By using the decorator you have a very descriptive way of marking methods as final.
Working example
Edit: As Mark pointed out, this only works when transpiling to ES5 or earlier.
There is no final keyword, but you can make use of readonly in the following ways:
Assign once
class IFACE {
constructor(public a: number, readonly b: number) {}
}
let test: IFACE = new IFACE(1, 34);
test.a = 5; // OK
// test.b = 2; // Error
console.log(test.a, test.b); // 5 34
Disable overriding
class IFACE {
constructor(public a: number, readonly b: number) {
// console.log(`b is ${this.b}`);
this.b = 2; // b is always 2
// console.log(`b is ${this.b}`);
}
}
let test: IFACE = new IFACE(1, 34);
test.a = 5;
console.log(test.a, test.b); // 5 2
Not sure if the last one is a bug seeing as you are assigning to a readonly field twice - once in the constructor parameter, and once in the constructor body.
Note you can change the last one to this if the double assignment bothers you as much as it did me:
class IFACE {
a: number;
readonly b: number = 2;
constructor(a: number) { this.a = a; }
}