【问题标题】:Why are rest parameters undefined in TypeScript?为什么 TypeScript 中未定义剩余参数?
【发布时间】:2020-03-03 00:11:02
【问题描述】:

我有一个使用 TypeScript (3.6.3) 编程的 React Native 应用程序。我有以下代码(实际代码来自 API 库,但这是一个最小的可重现示例):

class Base{
    someVal: string[];
    constructor() {
        this.someVal = [];
    }
    someMethod<T extends Base>(this: T, ...someArgs:string[]){
        debugger;
        this.someVal = someArgs;
    }
}

class Derived extends Base{

}

let myVar = new Derived().someMethod('hello');

代码完全模仿库代码,并且行为相同(错误)。没有编译器错误或警告。当我运行代码时,我希望someArgs['hello'],但它是undefined。另外,我有一个 arguments 数组,其中包含 ['hello'] 的实际值:

此时代码(由 Babel 动态编译)就像 Javascript(因此,未定义的实际变量和幻像参数变量)。为什么它没有正确转译,我该如何解决? (我在 Babel 核心/运行时 7.6.2)

这是生成的index.bundle的相关代码:

    var Base = function () {
    function Base() {
      (0, _classCallCheck2.default)(this, Base);
      this.someVal = [];
    }

    (0, _createClass2.default)(Base, [{
      key: "someMethod",
      value: function someMethod() {
        debugger;

        for (var _len = arguments.length, someArgs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
          someArgs[_key - 1] = arguments[_key];
        }

        this.someVal = someArgs;
      }
    }]);
    return Base;
  }();

  var Derived = function (_Base) {
    (0, _inherits2.default)(Derived, _Base);

    function Derived() {
      (0, _classCallCheck2.default)(this, Derived);
      return (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(Derived).apply(this, arguments));
    }

    return Derived;
  }(Base);

  var myVar = new Derived().someMethod('hello');

【问题讨论】:

  • 您的代码似乎在 Typescript 操场上运行良好。
  • @Pointy 是的,可能。但它不是,当用 Babel 编译时。
  • 那么 JavaScript 是什么样的?在操场上看起来不错(当然)。
  • @Pointy 它产生了一个大胖子index.bundle,如果你需要的话,我已经用相关部分更新了问题。
  • 很明显,生成的代码完全是错误的。它将this 参数视为实际的正式参数。

标签: javascript typescript react-native babeljs


【解决方案1】:

为什么它没有正确转译,我该如何解决? (我在 Babel 核心/运行时 7.6.2 上)

代码被“正确”地转译,因为它在执行时会正常运行,但正如您所见,当使用调试器检查输出代码时,它的运行方式与您期望的不同。不幸的是,没有简单的方法解决这个问题。

someMethod<T extends Base>(this: T, ...someArgs:string[]){
    debugger;
    this.someVal = someArgs;
}

变成

value: function someMethod() {
  debugger;

  for (var _len = arguments.length, someArgs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
    someArgs[_key - 1] = arguments[_key];
  }

  this.someVal = someArgs;
}

因为 Babel 延迟生成 someArgs 数组,直到使用数组之前的最后一刻(在这种情况下,当它被分配时)。在这种情况下,这最终是 after 你的 debugger 声明。这样做是因为函数中可能存在从未实际使用过someArgs 的分支,如果从未使用过该数组,将arguments 转换为数组将浪费性能。

如果您进入调试器直到到达this.someVal = someArgs; 行,您会看到someArgs 具有您期望的值。

【讨论】:

  • 不,当我把debugger放在赋值之后,someArgs变成了一个空数组,这是不正确的。我尝试添加第二个元素 (let myVar = new Derived().someMethod('hello', 'world');),然后它变成一个包含一个元素 world 的数组。它似乎省略了我通过的第一个元素。
  • @CanPoyrazoğlu 抱歉,这回答了“为什么在 TypeScript 中未定义剩余参数?”,但我什至没有注意到您得到的项目数量错误。不正确的参数数组会导致错误:github.com/babel/babel/issues/8840
  • 是的,我同时也发现了github.com/babel/babel/pull/9714,涵盖了同样的问题。我刚刚通过将一个空的 { } 对象作为第一个参数传递给我的函数来“解决”这个问题,这适用于我的情况。
【解决方案2】:

显然,这确实是一个 Babel 错误,它有一个尚未合并到 master 的开放 PR:https://github.com/babel/babel/pull/9714:

TypeScript“这个参数”是一个假参数,不应该是 计算函数参数时考虑。这个补丁 通过使用从 transform-typescript 获取的条件跳过它 插件。

注意:因为 transform-typescript 插件正在移除这种 参数,包括它在转换参数插件解决之前 问题。此补丁修复了其他情况下的问题。

【讨论】:

    猜你喜欢
    • 2019-02-07
    • 2014-01-31
    • 2019-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多