Ошибка типскрипта? `эта` разница между синтаксисом `get` и `get` в `defineProperty`

У меня есть этот код:

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);

Когда я запускаю это как JavaScript в браузере или в NodeJS, я получаю вывод:

5
9
5
9

Когда я запускаю тот же код, что и TypeScript (см. https://repl.it/repls/TornHomelyThing) , я получаю вывод:

undefined
9
5
9

I also see what JS TS generates from it @ https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=22&pc=1#code/G4QwTgBAHhC8EG8oEYBcECsAaaAmdA7AL4DcAUGaJAJ5yJkQQB0LUODEA+gPZgCWAcz4A7EABsAGvihMoudowEBTAC54AFAEoEHRgGNuwgM7cxSpmO4D1KgBZ8js5JvKNGYVQFcwwiAE5XCCIyUjIDY1NzS2tqWVwXCioIAC86HUYWWQUuXkERcSlUGTkQ8gB5ACMAKyU9FSYAEyUAMxElAAUwbgAHJTAVanVknAByORGcBAhlFXRmz2E6vkMtejcIcJMzCysbe0cUBPWPFW9fAI4iIM0wwy2o3eS4hKA .

Мой вопрос двоякий:

  1. Следует ли считать это ошибкой в ​​TypeScript, учитывая, что один и тот же код в JS ведет себя по-разному?
  2. Есть ли веская причина, по которой this не может ссылаться на x1 в сгенерированном TypeScript JS? Или это ошибка самого JS?

person SBhojani    schedule 26.03.2020    source источник
comment
Это действительно похоже на ошибку в компиляторе машинописного текста. Стоит отметить: если вы установите цель машинописного текста на es2018 или новее, он будет работать нормально.   -  person elderapo    schedule 26.03.2020
comment
Yes it is check out the complied code from this typescript playground typescriptlang.org/play/   -  person Code Maniac    schedule 26.03.2020


Ответы (1)


Следует ли считать это ошибкой в ​​TypeScript, учитывая, что один и тот же код в JS ведет себя по-разному?

Да, это определенно похоже на ошибку, связанную с транспиляцией Typescript синтаксиса распространения объектов. Скомпилированный TS не делает то же самое, что JS.

В первом вы определяете объект y со свойством x2, который является геттером:

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

Таким образом, ссылка на y.x2 позже приводит к вызову геттера. Но в скомпилированном Typescript мы получаем:

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

Это приведет к тому, что геттер будет вызываться немедленно — геттеры вызываются, когда объект передается в качестве второго или более аргумента внутри Object.assign. И когда геттер вызывается, 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');
    }
};
person CertainPerformance    schedule 26.03.2020
comment
Обнаружена существующая ошибка TS для этого @ github.com/microsoft/TypeScript/issues/24799 . - person SBhojani; 26.03.2020