TypeScript 计算键具有私有元素和超级调用在目标为ES2022时不应被提升,

mccptt67  于 6个月前  发布在  TypeScript
关注(0)|答案(6)|浏览(57)

🔎 搜索词

私有元素,计算键,超类调用

🕗 版本与回归信息

  • 这是一场崩溃
  • 在版本______和______之间发生了变化
  • 在提交或PR______中发生了变化
  • 这是我尝试的每个版本的行为,我查阅了关于类的FAQ条目
  • 由于______,我无法在之前的版本上测试这个

⏯ Playground链接

https://www.typescriptlang.org/play?target=9#code/DYUwLgBAxghgDmArgJxAEwGIHssEEpQgDORANBKkYsGANwBQUwMJEAQhAN70TRYB2RMMkRQwWZAAoAbgEouPXtHhJUmHPkKsAvBGmKAvvSP1+IAO7RmrAMIQQADzAh+aIuwW8oAoSLETJeW4lKxZ3XE8QiCEYMABLKAgAYgAzHAhdABYAJgYo6LBYhIgAbSo4EClJMHltAD4IMAA6VJxZAF08pQMu3kpqSF1YBBR0bDwCYiJJXFlaXkNjekYfLFAm4CwAc0lOCmIBiAM5oA

💻 代码

let capturedFooAccess, result;
class B {
  constructor(v) {
    capturedFooAccess = v
  }
}

new class C extends B {
  constructor() {
    class A {
      static #foo = 42;
      static [super((t) => t.#foo)];
    };
    result = capturedFooAccess(A);  
  }
}

console.log({ result });

🙁 实际行为

转换后的代码抛出 "Private field '#foo' must be declared in an enclosing class" 错误,因为私有的IIFE在类 A 之前被提升。

🙂 预期行为

它应该打印 { result: 42 }
输入已经是ES2022,TS可以保持原样。

关于问题的附加信息

我们可以在ES2022目标中避免这个问题,但我还没有弄清楚如何处理装饰器表达式。要么我们失去了 #foo 的访问权限,要么 super() 被移动到了未派生类 A 的范围。

bvhaajcl

bvhaajcl1#

翻译结果为:它应该打印$x^1m0n^1x$

输入已经是ES2022,TS可以保持原样。

这就是我观察到的行为:

https://www.typescriptlang.org/play?target=9&filetype=js#code/DYUwLgBAxghgDmArgJxAEwGIHssEEpQgDORANBKkYsGANwBQUwMJEAQhAN70TRYB2RMMkRQwWZAAoAbgEouPXtHhJUmHPkKsAvBGmKAvvSP1+IAO7RmrAMIQQADzAh+aIuwW8oAoSLETJeW4lKxZ3XE8QiCEYMABLKAgAYgAzHAhdABYAJgYo6LBYhIgAbSo4EClJMHltAD4IMAA6VJxZAF08pQMu3kpqSF1YBBR0bDwCYiJJXFlaXkNjekYfLFAm4CwAc0lOCmIBiAM5oA

cu6pst1q

cu6pst1q2#

这是我观察到的行为:https://www.typescriptlang.org/play?target=9&filetype=js#code/DYUwLgBAxghgDmArgJxAEwGIHssEEpQgDORANBKkYsGANwBQUwMJEAQhAN70TRYB2RMMkRQwWZAAoAbgEouPXtHhJUmHPkKsAvBGmKAvvSP1+IAO7RmrAMIQQADzAh+aIuwW8oAoSLETJeW4lKxZ3XE8QiCEYMABLKAgAYgAzHAhdABYAJgYo6LBYhIgAbSo4EClJMHltAD4IMAA6VJxZAF08pQMu3kpqSF1YBBR0bDwCYiJJXFlaXkNjekYfLFAm4CwAc0lOCmIBiAM5oA
哦,我没想到复制粘贴还有一个要求:语言选项应该设置为“TypeScript”,(你的是JavaScript)。

cig3rfwq

cig3rfwq3#

我注意到,选择TS会改变emit。这几乎肯定是一个bug。

ffdz8vbo

ffdz8vbo4#

哦,这是一个仅限于TS的问题,因为当我启用useDefineForClassFields选项时,输出是好的。

tez616oj

tez616oj5#

它(uDFCF)应该在tsc中默认启用,以便目标为es2022+(我记得是这样的),但是不幸的是,playground中没有这个标志的"默认"开关,需要在playground中手动设置。

z9ju0rcb

z9ju0rcb6#

我们目前报告一个错误,如果你在类元素计算属性名称中使用 this ,因为它可能被认为是模糊的,不知道你指的是哪个 this 。出于同样的原因,我们也应该将其视为错误来引用 super
useDefineForClassFieldsfalse 时,我们必须移动一些东西以确保保留评估顺序。这意味着在尝试避免将逻辑注入到计算属性名称中时,在 static {} 块中评估一些东西,因为这会产生不可读的代码。虽然这里的 emit 绝对是个 bug ,但使用 static {} 在这里生成期望的输出有点复杂,因为将捕获 super 的箭头移动到 static {} 块中会改变其含义。
为了保留作用域和评估顺序,我们需要发出的东西类似于这样:

"use strict";
let capturedFooAccess, result;
class B {
    constructor(v) {
        capturedFooAccess = v;
    }
}
new class C extends B {
    constructor() {
        var _a;
        _a = (...args_1) => super(...args_1); // lexical `super` capture
        class A {
            static { _a((t) => t.#foo); } // evaluation before initializers are run

            static #foo = 42;
        }
        ;
        result = capturedFooAccess(A);
    }
};
console.log({ result });

这似乎是一个多余且不必要的转换;然而,如果你修改示例以包含具有计算名称的静态字段的初始化器(例如,static [super(...)] = 1),就会更明显地了解为什么我们会进行这种转换:

"use strict";
let capturedFooAccess, result;
class B {
    constructor(v) {
        capturedFooAccess = v;
    }
}
new class C extends B {
    constructor() {
        var _a, _b;
        _b = (...args_1) => super(...args_1); // lexical `super` capture
        class A {
            static { _a = _b((t) => t.#foo); } // evaluation and capture of property name before
                                               // initializers are run

            static #foo = 42;
            static { this[_a] = 1; }           // Set-based initialization of static field
        }
        ;
        result = capturedFooAccess(A);
    }
};
console.log({ result });

相关问题