Microsoft/TypeScript

Class field initialization order different between target ES2021 and ES2022

Open

#52,331 创建于 2023年1月20日

在 GitHub 查看
 (8 评论) (13 反应) (0 负责人)TypeScript (6,726 fork)batch import
Experience EnhancementHelp WantedSuggestion

仓库指标

Star
 (48,455 star)
PR 合并指标
 (平均合并 6天 17小时) (30 天内合并 9 个 PR)

描述

Bug Report

🔎 Search Terms

ES2022 class field initialization order

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about _________

⏯ Playground Link

Playground link with relevant code

💻 Code

interface Param {
  a: number;
}

class Test {
  // constructor that sets a field
  constructor(private param: Param){
  }

  // use that field to set another field
  a = this.param.a;
}

const t = new Test({a: 10});
console.log(t.a);

🙁 Actual behavior

If the compiler is set to target "ES2021" then the output will be:

"use strict";
class Test {
    constructor(param) {
        this.param = param;
        this.a = this.param.a;
    }
}
const t = new Test({ a: 10 });
console.log(t.a);

If the target is set to "ES2022" then the output will be:

"use strict";
class Test {
    param;
    constructor(param) {
        this.param = param;
    }
    a = this.param.a;
}
const t = new Test({ a: 10 });
console.log(t.a);

These look logically the same, just utilizing the field syntax in Javascript, but in Javascript fields are initialized BEFORE the constructor is run.

So that means that ES2021 will work, setting the param field on Test and then use it to set the a field, but with ES2022 it will attempt to set a first, using the param field which has not been initialized yet, thus throwing an error at runtime.

There is no warning or error that this will happen, and I could not find any kind of compiler flag to enable such an error. Even "strictPropertyInitialization" didn't catch this like I thought it might.

🙂 Expected behavior

In order to maintain Javascript semantics, I believe that Typescript should not allow field initializers to access these automatic field setting constructor parameters. Typescript should not allow you to do something that will simply not work.

Alternatively, the compiler could be changed to insert the initializer at the end of the constructor. This would maintain existing Typescript behavior at the expense of being different from Javascript.

贡献者指南