TypeScript 计算属性在对象/类评估期间没有正确绑定,

s71maibg  于 5个月前  发布在  TypeScript
关注(0)|答案(8)|浏览(82)

TypeScript Version: 3.2.0-dev.20181011
Search Terms: computed property expression
Code

const classes = [];
for (let i = 0; i <= 10; ++i) {
  classes.push(
    class A {
      [i] = "my property";
    }
  );
}
for (const clazz of classes) {
  console.log(Object.getOwnPropertyNames(new clazz()));
}

Expected behavior: The log statements indicate that each class in classes has a different property name ( i should be evaluated at the time of the class evaluation and all instances of that class should have a property name corresponding to that evaluation of i ).
Actual behavior: Compiled code logs:

[ '10' ]
[ '10' ]
[ '10' ]
[ '10' ]
[ '10' ]
[ '10' ]
[ '10' ]
[ '10' ]
[ '10' ]
[ '10' ]
[ '10' ]

Playground Link

mkshixfv

mkshixfv1#

在计算属性的行上存在类型错误:
类属性声明中的计算属性名称必须引用类型为字面类型或“唯一符号”类型的表达式。
然而

  • 尽管存在类型错误,但仍然有可能产生正确的emit(如果这是可取的)
  • class fields proposal 允许像示例中那样编写代码。Chrome Canary实现了该规范,并为示例代码产生了预期的输出。
js4nwp54

js4nwp542#

Taking PRs and marking it as moderate (assuming you are familiar with spec-reading and the transform pipeline).

roejwanj

roejwanj3#

消除类型错误会产生什么影响?允许在计算字段声明中使用任意字符串和符号值是否会影响推断?

r1zk6ea1

r1zk6ea14#

除了类型错误之外,这里有一个可能的发射器,它可以正确地工作。我还没有看到其他使用这种参数调用IIFE的情况。有吗?

$x_1a^0b^1x$

x759pob2

x759pob25#

也许我们可以利用已经完成的iife内容来转译letconst
当针对ES2015目标生成Joey示例的当前代码为:

var _a, _b;
"use strict";
const classes = [];
for (let i = 0; i <= 10; ++i) {
    classes.push((_b = class A {
            constructor() {
                this[_a] = "my property";
            }
        },
        _a = i,
        _b));
}
for (const clazz of classes) {
    console.log(Object.getOwnPropertyNames(new clazz()));
}

如果我们将_a_b移动到类的包含范围内,并使用let,则输出是正确的:

"use strict";
const classes = [];
for (let i = 0; i <= 10; ++i) {
    let _a, _b; // <---- was moved
    classes.push((_b = class A {
            constructor() {
                this[_a] = "my property";
            }
        },
        _a = i,
        _b));
}
for (const clazz of classes) {
    console.log(Object.getOwnPropertyNames(new clazz()));
}

更新:这会是一个大的架构变化吗?如果我理解正确,lexicalEnvironmentStack用于提升声明,并且在transformer.ts中定义,而不是在特定的转换器中。

swvgeqrz

swvgeqrz6#

在ES2015之前,TypeScript转换器中发生了特殊的临时变量和提升。也许我们需要一个块级提升?

v1l68za4

v1l68za47#

@Kingwl同意了。我们在joeywatts#15中尝试了这种方法,并在#28708中使用了这种方法。

kt06eoxx

kt06eoxx8#

我注意到在迭代语句内的类表达式中,属性声明初始化器的绑定也存在问题。例如:

let arr = [];
for (let i = 0; i < 5; ++i) {
  arr.push(class C {
    test = i;
  })
}
arr.forEach(clazz => console.log(new clazz().test));

由于 i 是在循环内的作用域范围内的块级作用域,每个类都应该捕获其自己的 i 值(导致它打印 0、1、2、3、4)。当目标为 ES5 或更低版本时,TypeScript 编译器目前不会保留这种绑定。这目前不会产生编译错误,并在目标为 ES2015 与 ES5 时导致不同的运行时行为。
我已经调查了为了捕捉这种绑定所需的检查器更改,我认为只需对 checkNestedScopeBinding 函数进行简单的更改以适应示例属性初始化器中的使用位置(除了函数之外)即可。我是否应该为此打开一个单独的问题?

相关问题