使用构造函数简写属性初始化字段时ts-node与编译JS的执行差异问题
参数属性与类字段初始化顺序不一致:ts-node 与 tsc 编译结果差异问题
问题重现
我编写了如下TypeScript代码:
class A { constructor(readonly parameterProperty: number) {} readonly fieldInitializer = this.parameterProperty * 10; }
这段代码在ts-node中运行完全正常,parameterProperty会先被初始化,接着fieldInitializer能正确拿到它的值计算出结果。但用tsc编译为JavaScript后,执行时fieldInitializer会得到NaN——查看编译后的代码发现,类字段fieldInitializer的初始化逻辑被放在了参数属性赋值之前:
"use strict"; class A { parameterProperty; constructor(parameterProperty) { this.parameterProperty = parameterProperty; } fieldInitializer = this.parameterProperty * 10; }
此时fieldInitializer计算时parameterProperty还未被赋值,因此结果不符合预期。
我的tsconfig配置如下:
{ "target": "ES2022", "module": "CommonJS", "emitDecoratorMetadata": true, "experimentalDecorators": true, "esModuleInterop": true }
问题原因
这个差异源于TypeScript在启用experimentalDecorators且目标版本为ES2022+时的类字段初始化逻辑:ES2022的类字段语法默认会在构造函数执行前初始化字段,但参数属性的赋值逻辑是在构造函数内部。而ts-node的内部处理逻辑没有遵循这个顺序,仍保持了参数属性优先初始化的行为。
解决方案
在tsconfig.json中添加"useDefineForClassFields": false配置项,强制TypeScript使用旧的类字段初始化逻辑,将类字段的初始化代码移到构造函数内部、参数属性赋值之后:
{ "target": "ES2022", "module": "CommonJS", "emitDecoratorMetadata": true, "experimentalDecorators": true, "esModuleInterop": true, "useDefineForClassFields": false }
添加该配置后,重新编译的JavaScript代码会将fieldInitializer的初始化逻辑放在构造函数内部的参数属性赋值之后,与ts-node的运行表现一致。
内容的提问来源于stack exchange,提问作者Aderion
相关产品推荐
相关产品推荐

