TypeScript:在类中标记为只读的属性实际上被覆盖
我正试图在TypeScript中对readonly关键字进行思考。在我的理解中,在调用构造函数之后,只读属性将不可写,但是当我测试时,我实际上可以覆盖它。编译器给出了有关“无法分配给'doNoTChange',因为它是只读属性”,“属性'doNoTChange'是私有的,只能在类'readOnlyClass'中访问””的错误,但代码仍会编译并运行。所以我的问题是,这正常吗?有没有办法防止覆盖 我在Vue中使用TypeScript,只是为了澄清一下 这是我正在测试的实际代码。我正在App.vue文件的挂载钩子中进行测试(即,我没有更改vue CLI提供的默认文件结构) 使用Vue 2.6.11和TypeScript 3.5.3版TypeScript:在类中标记为只读的属性实际上被覆盖,typescript,vue.js,Typescript,Vue.js,我正试图在TypeScript中对readonly关键字进行思考。在我的理解中,在调用构造函数之后,只读属性将不可写,但是当我测试时,我实际上可以覆盖它。编译器给出了有关“无法分配给'doNoTChange',因为它是只读属性”,“属性'doNoTChange'是私有的,只能在类'readOnlyClass'中访问””的错误,但代码仍会编译并运行。所以我的问题是,这正常吗?有没有办法防止覆盖 我在Vue中使用TypeScript,只是为了澄清一下 这是我正在测试的实际代码。我正在App.vue文
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'
}
当您使用
tsc
编译TypeScript代码时,它同时执行类型检查和到JavaScript的传输,而这两者在很大程度上是相互独立的
编译器进行类型检查,以便在开发人员执行可能导致运行时出现问题的潜在错误时向他们提供警告。请注意,这些实际上只是警告;它们实际上并不能防止运行时出现问题。因此,当您分配给只读属性时,您会得到所需的警告:
Cannot assign to 'doNoTChange' because it is a read-only property.(2540)
这告诉你你可能想解决这个问题。它不会自行修复问题(这可能需要比合理编程到编译器中更多的智能),也不会编译没有问题的代码版本
编译器通过静态类型系统特性发出JavaScript,并以编译器选项指定的JavaScript目标版本输出剩余的运行时代码。这意味着运行时代码中根本不会出现纯类型系统特性readonly
。在JavaScript中找不到它。无论类型检查器发现多少错误,编译器都可以发出JavaScript。那是故意的
如果希望编译器在出现错误时不发出JavaScript,可以使用。如果无法使其工作,则应三倍检查编译器配置,并考虑生成A以便其他人可以看到相同的问题。
备份时,您遇到的问题可能是一般性的。在TypeScript中,如果您考虑您想要什么运行时代码,然后使用TypeScript为代码提供更强大的类型,这样您就可以在编写代码时从IDE获得一些指导,那么您通常会更高兴。在运行时,JavaScript将乐于尝试评估x.toUpperCase()
,无论x
是什么。如果你写让x:string代码>然后稍后x=15;x、 toUpperCase()
,编译器将在x=15
处警告您正在设置问题
那么,什么运行时代码的行为与您想要的一样呢?一个可能的候选方法是对doNoTChange
属性使用JavaScript。如果在没有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);
编译器错误和运行时错误
好的,希望这能给你一些指导;祝你好运
因此,感谢@jcalz answer和@marty的评论,他们都强调检查我的编译器选项,这是我问题的确切解决方案,但并不是那么直接,因为我不太擅长webpack,而且对TypeScript还是新手
步骤1:
@jcalz和@marty都建议为TypeScript添加/使用--noemitorror编译器选项。因此,我将它添加到我的tsconfig.json文件中,但它本身并没有解决这个问题,我不得不将它与下面的步骤2一起使用
步骤2:
我在GitHub上发现了完全相同的问题,答案是“您需要在中禁用异步选项”
因此,我按照链接进行操作,该链接显示我应该考虑对我的网页包构建进行一些配置,在进一步挖掘之后,我找到了解决方案的第二部分,即将下面的代码添加到我的vue.config.js文件中
因此,我的vue.config.js文件如下所示:
module.exports = {
lintOnSave: 'error',
chainWebpack: config => {
config.module
.rule('ts')
.test(/\.tsx?$/)
.use('ts-loader')
// .loader('ts-loader')
.tap( _ => {
return {
appendTsSuffixTo: [/\.vue$/],
// transpileOnly: true
};
})
.end();
},
}
您会注意到,我注释掉了行transpileOnly:true
,我只是想让其他人知道它,因为它给了我一些我没有立即注意到的问题,如果您将它设置为true,那么它将破坏整个目的并编译;在我的例子中,它是打印错误,但编译任何错误。这是我在阅读这里的文章后发现的,它说“如果您想显著加快编译速度,可以设置此标志。但是,您从应用程序中不同依赖项之间的静态类型检查中获得的许多好处将丢失。”
所以现在我的代码成功失败了。。。正如预期的那样如果启用(在编译器选项中将其设置为true),会发生什么情况。@Marty我只是尝试了该选项,它没有做任何更改,除非我做错了。首先,我将其命名为“noEmitOnError”:没错,在tsconfig.json文件的compilerOptions中,它没有改变任何内容,然后我尝试了“npm run serve--noEmitOnError”,但仍然没有改变,然后还尝试了两者,但仍然没有改变。谢谢,您的回答告诉我,我应该查看编译器选项,并引导我找到所需的完整解决方案(添加了答案)。我在投票