useDefineForClassFields设置为false后编译仍有问题

关于此问题我还阅读了以下内容

贺师俊的回答:https://www.zhihu.com/question/391196995
刘家忍的文章:https://zhuanlan.zhihu.com/p/258906525

@wangzhe 呼叫首席客服
@nantas
@boyue
@panda
@gameMaster

2生成了_this.age2 = void 0也没什么问题啊,如果你想像3这样不生成,可以class TestClass2 extends TestClass1 {
declare age2?: number; 这样写

你可能没明白我的意思。
1)3.0之前不需要写,为什么3.0之后需要这样写。
2)这是官方的编译器修改后产生的代码,所以我想从知道官方这么做的原因,为什么要多生成这一句,不生成其实就跟tsc的效果一致了。
3) useDefineForClassFields本身是可配置,所以使用上无所谓,关闭了就是。但是目前多了这一句,导致跟预期的不符。

2.x是tsc编译的,3.x是babel编译的。这个可能是tsc和babel之间的差别的,但我也不是很懂他们之间具体有多少差异

那我去试一下babel编译的效果。看看跟tsc编译的差多少。

babel编译

var TestClass2 = /*#__PURE__*/function (_TestClass) {
  _inherits(TestClass2, _TestClass);

  var _super = _createSuper(TestClass2);

  function TestClass2() {
    _classCallCheck(this, TestClass2);

    return _super.call(this);
  }

  _createClass(TestClass2, [{
    key: "init",
    value: function init() {
      _get(_getPrototypeOf(TestClass2.prototype), "init", this).call(this);

      this.age2 = 100;
      console.log("age2:".concat(this.age2));
    }
  }]);

  return TestClass2;
}(TestClass1);

也没看见有生成上面那一句

顶一下顶一下

3.x 内部使用 babel 编译代码。

Creator 选项 !useDefineForClassFields 对应 @babel/preset-env@babel/plugin-proposal-class-propertiesloose

Creator 选项 allowDeclareFields 对应 @babel/preset-typescriptallowDeclareFields


我使用最新的 babel 测试了所有组合的情况,发现它们都会将 age2 初始化为 undefined。以下是我的测试代码:

babel-test.zip (23.9 KB)

如楼上所说,你可以 declare age2: undefined | number 让它不初始化为 undefined

useDefineForClassFields为false时不使用@babel/plugin-proposal-class-properties

const babel = require('@babel/core');
const fs = require('fs-extra');
const env = require('@babel/preset-env');
const ts = require('@babel/preset-typescript');
const classProperties = require('@babel/plugin-proposal-class-properties');

(async (input = './input.ts') => {
    await transform('false-false.js', false, false);

    async function transform(output, useDefineForClassFields, allowDeclareFields) {
        const loose = !useDefineForClassFields;
        let plugins = [];
        //如果为false不使用plugin
        if (useDefineForClassFields) {
            plugins.push([classProperties, { loose }]);
        }
        const result = await babel.transformFileAsync(
            input,
            {
                presets: [
                    [env, { loose }],
                    [ts, { allowDeclareFields }],
                ],
                plugins: plugins,
            }
        );
        await fs.writeFile(output, result.code);
    }
})();

编译出来就不会有那一句

"use strict";

function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

var TestClass1 = /*#__PURE__*/function () {
  function TestClass1() {
    this.init();
  }

  var _proto = TestClass1.prototype;

  _proto.init = function init() {
    this.age1 = 10;
    console.log("age1:" + this.age1);
  };

  return TestClass1;
}();

var TestClass2 = /*#__PURE__*/function (_TestClass) {
  _inheritsLoose(TestClass2, _TestClass);

  function TestClass2() {
    return _TestClass.call(this) || this;
  }

  var _proto2 = TestClass2.prototype;

  _proto2.init = function init() {
    _TestClass.prototype.init.call(this);

    this.age2 = 100;
    console.log("age2:" + this.age2);
  };

  return TestClass2;
}(TestClass1);

其实诉求很简单,就是在不使用这个选项的时候,和之前行为一致就行。不需要再额外写一个declare。虽然简单且解决问题,但是麻烦。

848b43eaf2e1abf539782e97ccdb45d

今晚发现一个bug,看看这个能解决嘛? 还是说只能避开 ?

@shrinktofit 这个看下. 如果useDefineForClassFields为false, 则不使用这个plugin就不会生成了.
我看了3.4.1依旧是会生成 .

loose 有没有设置为 “true”?

const loose = !useDefineForClassFields;
useDefineForClassFields为false, loose当然是true了.
一样会生成.

只要使用了这个插件 不管loose是true还是false,一定会生成
_this.age2 = void 0;

如下:

var TestClass2 = /*#__PURE__*/function (_TestClass) {
  _inheritsLoose(TestClass2, _TestClass);

  function TestClass2() {
    var _this;

    _this = _TestClass.call(this) || this;
    _this.age2 = void 0; // 这边这个
    return _this;
  }

  var _proto2 = TestClass2.prototype;

  _proto2.init = function init() {
    _TestClass.prototype.init.call(this);

    this.age2 = 100;
    console.log("age2:" + this.age2);
  };

  return TestClass2;
}(TestClass1);

但是如果在 useDefineForClassFields=false的情况下,不使用这个插件. 则不会生成.

3.5 会修复这个问题。3.5 之后:

符合规范的类字段 允许声明类字段 未指定初始化式的字段 初始化语义
使用 Define 语义初始化为 undefined Define
使用 Set 语义初始化为 undefined Set
不生成代码 Define
不生成代码 Set

其中:

  • 初始化语义 Define 是指使用 Object.defineProperty() 定义、初始化类字段;

  • 初始化语义 Set 是指使用 this./* 字段名 */ = /* 初始化式 */ 初始化类字段;

  • 不生成代码是指这段代码不起作用,相当于没写。


另外,只要字段上面使用了装饰器。都会用 Define 语义来初始化。

1赞

308FF9E0

该主题在最后一个回复创建后14天后自动关闭。不再允许新的回复。