TypeScript:为什么我可以在构造函数中修改 `readonly` 属性?

Hit*_*mar 14 typescript

我有以下打字稿片段:

class Jedi { 
  private readonly name: string = 'Skywalker';
  constructor(name: string) { 
    this.name = name; //Why I am able to modify name.
  }
  toString():string {
    return this.name;
  }
}

var jedi = new Jedi('Kenobi');

console.log(jedi.toString()); //Kenobi
Run Code Online (Sandbox Code Playgroud)

正如您在代码中看到的,我已将name属性声明为readonly. 据我所知,将属性声明为我们readonly在 TypeScript 中使用的常量。一旦我们用初始化声明它,我们就不能修改它。

但是正如您在 constructor 它正在修改中所看到的那样。此外,TypeScript 编译器也不会对此发出警告。不确定这是 TypeScript 中的错误还是有意为之。谁能解释一下?

Seb*_*ald 11

文档只说

只读属性必须在其声明或构造函数中初始化。(来源

但正如 Romain 指出的,TypeScript 2.0 发行说明中有更多信息:

只读属性可能有初始值设定项,并且可以在同一个类声明中的构造函数中赋值,但不允许对只读属性赋值。(来源


让我困惑的是编译后的输出。请参阅TS Playground上的示例。

正如您所看到的,初始(只读)属性在编译时被覆盖,而没有来自 TS 的任何警告。我猜这是故意的,因为语言的行为一直都一样,而且边缘情况更少。

编辑:还有一种“糖化”的方式来初始化classTypeScript 中的属性(我想你知道但无论如何):

public/添加private到构造函数签名的参数会将这些参数初始化为类属性。所以在你的例子中:

class Jedi { 
    constructor(
        private readonly name: string = 'Skywalker'
    ) {}

    toString():string {
        return this.name;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果让 TypeScript 编译上面的代码,它实际上会按预期工作(或者至少是我期望的那样)。还有另一个指向操场的链接

tl;博士; 如果没有给出,则通过public/初始化构造函数签名内的类属性private将设置默认值。如果您“手动”设置类属性 ( this.name = name),这将不起作用。后者可能仍然不是错误而是有意的行为,因为您显式设置了类属性。

您可以通过启用noImplicitAnystrictNullChecks. 这样 TypeScript 会让你知道你的类属性可能是undefined.


readonly如果您想拥有不变性,我建议不要使用属性。不仅上面提到的有点奇怪的行为,一些经验不足的开发人员还可能认为readonly数组/对象在它不是的地方真的完全冻结/只读。而是使用类似ImmutableJS 的东西。