首页 > 解决方案 > TypeScript:在类中标记为只读的属性实际上被覆盖

问题描述

我正试图围绕 TypeScript 中的readonly关键字。据我了解,在调用构造函数后,只读属性将不可写,但当我测试时,我实际上可以覆盖它。编译器给出了有关“无法分配给 'doNoTChange' 因为它是一个只读属性”和“属性 'doNoTChange' 是私有的并且只能在类 'readOnlyClass' 中访问”的错误,但无论如何代码都会被编译并运行。所以我的问题是,这是正常的吗?有没有办法防止覆盖?

我在 Vue 中使用 TypeScript,只是为了澄清。

这是我正在测试的实际代码。我正在 App.vue 文件的挂载钩子中进行测试(即,我没有更改 Vue CLI 给出的默认文件结构)

使用Vue 2.6.11TypeScript 3.5.3 版

mounted() {
   /** Class definition */
   class readOnlyClass {
       readonly doNoTChange: string;
       constructor(ss: string) {
        this.doNoTChange = ss;
       }
   }

   /** Creating and loggin object */
   let test = new readOnlyClass('aaa'); 
   console.log(test.doNoTChange); // outputs 'aaa'

   /** Overwritting and logging the changed property */
   test.doNoTChange = 'after change';
   console.log(test.doNoTChange); // outputs 'after change'
}

标签: typescriptvue.js

解决方案


当您使用 编译 TypeScript 代码时tsc,它会进行类型检查转译为 JavaScript,这些在很大程度上是相互独立的。

编译器会进行类型检查以向开发人员提供警告,如果他们正在做一些可能导致运行时出现问题的潜在错误。请注意,这些实际上只是警告;它们实际上并不能防止运行时出现问题。因此,当您分配给readonly属性时,您会收到所需的警告:

Cannot assign to 'doNoTChange' because it is a read-only property.(2540)

这告诉您您可能想要解决问题。它本身并不能解决问题(这可能需要比合理编程到编译器中更多的智能)并编译没有问题的代码版本。

编译器通过擦除静态类型系统功能并在编译器选项指定的任何目标 JavaScript 版本中输出剩余的运行时代码来生成 JavaScript。这意味着readonly,纯类型系统功能根本不会出现在运行时代码中。你不会在 JavaScript 中找到它。无论类型检查器发现多少错误,编译器都可以发出 JavaScript。那是故意的。

如果您希望编译器在出现错误时发出 JavaScript,您可以使用编译--noEmitOnError器选项。如果你不能让它工作,你应该三重检查你的编译器配置并考虑生成一个可重现的示例,以便其他人可以看到同样的问题。


备份,您遇到的问题通常可能与类型擦除有关。在 TypeScript 中,如果您想到自己想要的运行时代码,然后使用 TypeScript 为该代码提供更强大的类型,那么您通常会更开心,这样您在编写代码时就可以得到 IDE 的一些指导。x.toUpperCase()在运行时,无论是什么,JavaScript 都会愉快地尝试评估x。如果您编写let x: string;,然后稍后x = 15; x.toUpperCase(),编译器将警告您x = 15您正在为自己设置一个问题。

那么,哪些运行时代码会表现得如您所愿?一个可能的候选者是对属性使用JavaScript getter doNoTChange如果你创建了一个没有 setter 的 getter,那么当你尝试设置属性时会出现运行时错误。代码可能会更改为:

class readOnlyClass {
  private _val: string;
  get doNoTChange(): string {
    return this._val;
  }
  constructor(ss: string) {
    this._val = ss;
  }
}

--target如果您是,则编译为以下代码ES2017

class readOnlyClass {
    constructor(ss) {
        this._val = ss;
    }
    get doNoTChange() {
        return this._val;
    }
}

然后你会得到这种行为:

let test = new readOnlyClass('aaa');
console.log(test.doNoTChange); // outputs 'aaa'

test.doNoTChange = 'after change'; // compile error here, and at runtime:
// TypeError: setting getter-only property "doNoTChange"
console.log(test.doNoTChange); 

编译器错误运行时错误。


好的,希望能给你一些方向;祝你好运!

链接到代码


推荐阅读