【问题标题】:Why `downlevelIteration` is not on by default?为什么`downlevelIteration`默认不开启?
【发布时间】:2019-04-25 17:56:37
【问题描述】:

当使用扩展运算符...Iterator 转换为Array 以ES5 为目标时,它会显示使用-downlevelIteration 编译器选项的错误。一旦开启,spread 操作符似乎可以完美运行。

我想知道为什么需要指定这个?除了添加更多从 tslib 发出的生成代码之外,启用它是否有任何缺点/限制?

另一个例子:动态创建 N 数组(例如 3):

[...Array(3).keys()]  // output: [0, 1, 2]

在 VS Code 中显示错误:

来自tsc 的错误消息:

Type 'IterableIterator' 不是数组类型或字符串类型。使用编译器选项“--downlevelIteration”来允许迭代器的迭代。

Edit and view the code and error in TypeScript Playground

【问题讨论】:

  • 哦,谢谢,所以正确的解决方案实际上是在tsconfig.json 中将target 设置为es6
  • @Klesun 您不能使用 es6 目标,因为如果需要支持 Internet Explorer 等旧版 js 运行时,它将会中断
  • 是的,虽然我相信大多数在这里使用谷歌搜索的人并不局限于这么旧的浏览器,但如果您根本没有tsconfig.json 文件,则默认情况下会出现此错误。
  • 我刚刚在 stackblitz.com 中使用了一个新的 TS 项目,其中目标是“esnext”,所以我对@Klesun 关于 es6 是解决方案的第一条评论感到困惑,但我找到了另一种解决方法这个具体代码是Array.from(Array(3).keys())
  • @Marcus 嗨,现在是 2021 年。我可以简单地将target 设置为es6 吗?

标签: typescript


【解决方案1】:

在阅读了release notes 和文章Downlevel Iteration for ES3/ES5 in TypeScript 之后,我相信这个问题的答案是downlevelIteration 被禁用,因为您需要决定(通过配置)您希望TypeScript 如何处理兼容性代码的编译(以支持旧版本的 Javascript)。

正如文章中更冗长的解释所表明的那样,您必须决定是否希望 TypeScript 内联必要的辅助函数(简单,但可能导致更大的生产包大小),或者您是否希望配置 TypeScript使用tslib 作为依赖,然后调用它的外部方法。

我强烈建议您阅读Downlevel Iteration for ES3/ES5 in TypeScript 以更深入地了解......并且可能是您最初问题的替代解决方案。

【讨论】:

  • 当 Babel 用于 TypeScript 代码的编译而 TypeScript 编译器仅用于类型检查时,它变得很有趣。就是这种情况,即对于使用 Create React App 或 Vue CLI 创建的项目。我认为在这种情况下,Babel 无论如何都会处理“下级迭代”,因此应该在 tsconfig.json 中激活“下级迭代”......但是在 CRA 中,它在生成项目时没有启用......
【解决方案2】:

tl;dr:在你的情况下,使用

Array.from(Array(3).keys())

降级是 TypeScript 的术语,用于转换为旧版本的 JavaScript。该标志是为了支持更准确地实现现代 JavaScript 如何在旧 JavaScript 运行时中迭代新概念。

ECMAScript 6 添加了几个新的迭代原语:for / of 循环 (for (el of arr))、数组扩展 ([a, ...b])、参数扩展 (fn(...args)) 和 Symbol.iterator。如果存在Symbol.iterator 实现,--downlevelIteration 允许在 ES5 环境中更准确地使用这些迭代原语。

既然在问题中我们遇到了数组传播的情况,那么让我们来挖掘一下。这是一个数组展开:

// Make a new array who elements are 1 followed by the elements of arr2
const arr = [1, ...arr2];

根据描述,降级到 ES5 听起来很容易:

// The same, right?
const arr = [1].concat(arr2);

但是,在某些极少数情况下,情况明显不同。例如,如果一个数组中有一个“洞”,那么缺少的索引在展开时会创建一个自己的属性,但如果使用concat 构建则不会:

// Make an array where the '1' element is missing
let missing = [0, , 1];
let spreaded = [...missing];
let concated = [].concat(missing);
// true
"1" in spreaded;
// false
"1" in concated;

downlevelIteration 将使用 Symbol.iterator(如果存在)更准确地模拟 ES 6 行为。

更多信息和示例here

现在,在您的情况下,您不想仅仅为了生成基本范围而更改此行为。除了[...Array(3).keys()],你可以依赖Array.from(Array(3).keys())

【讨论】:

    猜你喜欢
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-03
    相关资源
    最近更新 更多