打字稿中的最终关键字?

Final keyword in typescript?

有什么方法可以让一个变量只能被赋值一次吗?像这样

interface IFACE {
  a: number;
  final b: number;
}

IFACEConstructor (a: number): IFACE {
  return {a: a, b: 1}
}

test = IFACEConstructor(2);
test.a = 5 // OK
test.b = 2 // Error

从1.4开始可用,你可以查看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应该按照article.

来实现

您可以获得 TypeScript 1.4 here

更新 1

当然,"const is not the same as final"。问题是 "Is there any way to make a variable available to be assigned only once?"。 所以,根据这个 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
}

并且,目前(2015 年 11 月)"const" 在我看来,这是完成上述任务的唯一方法,即开箱即用的打字稿。

对于那些投反对票的人 - 如果您有其他答案,请在此主题中与社区分享。

更新 2:只读

Typescript 2.0 中引入了 readonly 修饰符(感谢@basarat)。 可以初始化 它们在声明点或构造函数中。

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
    }
}

但正如@RReverser 在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.

您可以使用 set/get 来获得结果。

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 无法设置,因为它没有 setter.

TS 编译器不会警告你,但浏览器会抛出错误。

没有final关键字,但是可以通过以下方式使用readonly:

分配一次

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

禁用覆盖

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

不确定最后一个是否是错误,因为您两次分配给只读字段 - 一次在构造函数参数中,一次在构造函数主体中。

请注意,如果双重作业和我一样困扰你,你可以将最后一个更改为这个:

class IFACE {
    a: number;
    readonly b: number = 2;

    constructor(a: number) { this.a = a; }
}

您可以使用方法装饰器并将描述符对象的可写 属性 设置为 false。

function final(target: Object, key: string | symbol, descriptor: PropertyDescriptor) {
  descriptor.writable = false;
}

然后在包含最终方法的父 class 中使用装饰器。

class Parent {
  @final
  speak() {
    console.log('Parent speaking');
  }
}

如果您现在扩展父 class 并尝试覆盖它的 speak 方法,您将得到一个错误:

Error: "speak" is read-only

class Child extends Parent {
  // Error: "speak" is read-only
  speak() {
    console.log('Child speaking');
  }
}

通过使用装饰器,您可以使用一种非常具有描述性的方式将方法标记为 final。

Working example

编辑: 正如 Mark 所指出的,这仅在转译为 ES5 或更早版本时有效。

这也可以是一个临时解决方案

class ComponentBase {
// using # pattern, for easy replace when ts final will avaible
    #render(){
        return this;
    }
// just asign your method order to a readonly props or getter
    public readonly render = this.#render;

}
class Component extends ComponentBase {

    public override render(){}; //this make error on method pattern

}

new Component().render();