打字稿错误? `get` 语法和 `defineProperty` 的 `get` 之间的区别

TypeScript bug? `this` difference between `get` syntax and `defineProperty`'s `get`

我有这个代码:

var x = {
  x1: 5,
  x2: 7
};

var y = {
  ...x,
  _originalX2: x.x2,
  get x2() {
    console.log(this.x1);
    return 9;
  }
};
console.log(y.x2);

var z = {
  ...x,
  _originalX2: x.x2
};
Object.defineProperty(z, 'x2', {
  get: function() {
    console.log(this.x1);
    return 9;
  }
})
console.log(z.x2);

当我在浏览器或 NodeJS 中 运行 this as JavaScript 时,我得到输出:

5
9
5
9

当我 运行 使用与 TypeScript 相同的代码(参见 https://repl.it/repls/TornHomelyThing)时,我得到输出:

undefined
9
5
9

我也看到了 JS TS 从中生成了什么 @ https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=22&pc=1#code/G4QwTgBAHhC8EG8oEYBcECsAaaAmdA7AL4DcAUGaJAJ5yJkQQB0LUODEA+gPZgCWAcz4A7EABsAGvihMoudowEBTAC54AFAEoEHRgGNuwgM7cxSpmO4D1KgBZ8js5JvKNGYVQFcwwiAE5XCCIyUjIDY1NzS2tqWVwXCioIAC86HUYWWQUuXkERcSlUGTkQ8gB5ACMAKyU9FSYAEyUAMxElAAUwbgAHJTAVanVknAByORGcBAhlFXRmz2E6vkMtejcIcJMzCysbe0cUBPWPFW9fAI4iIM0wwy2o3eS4hKA .

我的问题有两个:

  1. 鉴于 JS 中的相同代码具有不同的行为,这是否被视为 TypeScript 中的错误?
  2. this 无法在 TypeScript 生成的 JS 中引用 x1 是否有充分的理由?或者,这是 JS 本身的错误吗?

Is this to be considered a bug in TypeScript given that the same code in JS has different behavior?

是的,这看起来确实像是与 Typescript 的对象传播语法转译相关的错误。编译后的 TS 和 JS 不一样。

首先,你用属性x2定义了一个y对象,这是一个getter:

var y = {
  ...x, 
  _originalX2:x.x2, 
  get x2(){

因此稍后引用 y.x2 会导致调用 getter。但是在编译的 Typescript 中,我们得到:

var x = { x1: 5, x2: 7 };
var y = Object.assign(
  Object.assign({}, x),
  {
    _originalX2: x.x2,
    get x2() {
      console.log(this.x1);
    }
  }
);

这将导致 getter 立即被调用 - getter 在作为第二个或更多参数传递的对象中时被调用 [= =19=]。当 getter 被调用时, this 引用第二个参数,这里的这个对象:

{
  _originalX2: x.x2,
  get x2() {
    console.log(this.x1);
  }
}

它没有 x1 属性,因此它记录 undefined

undefined 之前记录 Object.assign 完成,在您到达 console.log(y.x2); 的下一行之前。

举一个更简单的例子:

var y = {
  ...{}, 
  get prop(){
    console.log('should not be invoked immediately');
  }
};

被错误地转译为

var y = Object.assign({}, { get prop() {
        console.log('should not be invoked immediately');
    } });

如果你这样做是为了让 Typescript 转译对象传播语法,通过使目标超过 ES2017,它将起作用。例如,使用 ESNext,上面的内容被转换为:

var y = {
    ...{},
    get prop() {
        console.log('should not be invoked immediately');
    }
};