首页 > 解决方案 > 为什么在 Jest 中运行时 for..of 循环在 Iterables 上不起作用?

问题描述

我有以下打字稿代码:

const myMap = new Map([["name", 5]]);
for (const foo of myMap.values()) {
    console.log(foo);
}

当我直接在节点(v8.12.0)中运行此代码时,它可以工作并将“5”打印到控制台。

如果我在 Jest 测试中运行完全相同的代码,它永远不会执行 for 循环的内容。它运行 for 条件,然后跳过循环,从不实际枚举值。

这是为什么?Jest 使用的 JS 运行时(不是节点吗?)有什么不支持 for..of over iterables 的吗?

谢谢!

标签: jestjs

解决方案


经过很长时间的调查,我已经了解了这一点。关于解决方案的重要背景信息:

  1. 当使用 TypeScript 编译器针对较旧的 ECMAscript 版本(如 ES3 和 ES5 )时,默认情况下不支持使用for..of循环来迭代集合。Iterable如果你想使用for..ofwith Iterable,你必须定位比 ES5 更新的东西,或者使用--downlevelIteration flag.
  2. 要将 Jest 与 TypeScript 项目一起使用,请使用ts-jest。至少,我是。我认为您也可以以某种方式使用 babel,但我认为 ts-jest 是首选
  3. 使用 ts-jest 时,默认情况下它会尝试使用项目使用的 tsconfig.json 文件——据我所知,这意味着您正在使用的 jest.config.js 文件旁边的那个(或当前目录,如果您没有指定 jest.config.js 文件)。如果在项目目录中找不到 tsconfig.json 文件,它会使用默认的 TypeScript 编译器选项。默认编译器选项导致 TypeScript 编译器以 ES3 或 ES5 为目标(ts-jest 文档声称它默认为 ES3,但在这种情况下 ts-jest 会覆盖默认值为 ES5)。--downlevelIteration默认情况下未启用。

考虑到这一切,我发现 ts-jest 无法找到我的项目的 tsconfig.json 文件,因此它使用默认设置运行我的测试,这意味着针对 ES5 而不允许downlevelIteration,所以我所有的for..of循环Iterable不起作用。它找不到我的 tsconfig.json 文件的原因是因为我的 jest.config.js 文件位于不同的目录中(在树中较高的位置),即使我是从带有 tsconfig.json 文件的目录运行 jest, ts-jest 没有在“当前”目录中查找,而是在我为 jest.config.js 文件指向 jest 的目录中查找,该文件不包含 tsconfig.json。

我对此的解决方案是稍微修改我的目录结构并利用ts-jest的 tsConfig 选项告诉它在哪里可以找到我的 tsconfig.json 文件,这使得一切“神奇”地工作,因为我的 tsconfig.json 文件针对 es2018,它支持for..of迭代Iterable

我考虑过但很快被忽略的另一种解决方案是上述 tsConfig 设置的功能,可直接--downlevelIteration在 jest 配置中设置编译器选项。我选择不这样做是因为,虽然它可以解决这个特定问题,但它不会解决更大的问题,即我的 Jest 测试使用与生产代码不同的标志编译我的 TypeScript!碰巧的是,由此引起的唯一当前问题是我的for..of循环痛苦。

一个简短的后记:我最终在这个问题上取得进展的方式是偶然发现 ts-jest 中的诊断选项。将其设置为 true 后,当我尝试运行测试时,会显示如下错误:

TypeScript diagnostics (customize using [jest-config].globals.ts-jest.diagnostics option): src/foo.ts:163:47 - error TS2569: Type 'Map<Guid, FooInfo>' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.

似乎应该显示 TS 编译器错误(并导致测试失败),无论是否启用 ts-jest“诊断”但shrug


推荐阅读