TS2318: Не удается найти глобальный тип "AsyncIterableIterator" - асинхронный генератор

У меня есть асинхронный генератор:

async function* foo() {
  yield "wait...";
  await new Promise(r=>setTimeout(r, 900));
  yield new Promise(r=>setTimeout(()=>r("okay!"), 100));
}

async function main() {
  for await (let item of foo()) {
    let result = await item;
    console.log(result);
  }
}

main();

но с typescript 2.3 это дает мне ошибки:

ошибка TS2318: Не удается найти глобальный тип "AsyncIterableIterator". example.ts(10,26):

error TS2504: Тип должен иметь метод "Symbol.asyncIterator", который возвращает асинхронный итератор.

Как можно устранить эту ошибку и как запустить генератор асинхронов?

Ответ 1

Symbol.asyncIterator - это функция esnext; поэтому вы должны явно нацелить esnext или добавить библиотеку esnext.asynciterable для машинописного esnext.asynciterable для поддержки синтаксиса. Тем не менее, машинописный шрифт в настоящее время не занимается реализацией символов во время выполнения, поэтому вам нужно полифонировать.

Polyfill + Down-Compile

Добавить "esnext.asynciterable" в lib в tsconfig.json

{
  "compilerOptions": {
    "target": "es2015",
    "moduleResolution": "node",
    "module": "commonjs",
    "lib": [      
      "dom",
      "es2015",
      "esnext.asynciterable"
    ]
  }
}

вы можете полилизовать Symbol.asyncIterator, просто создав новый символ, прежде чем делать что-либо еще.

if(Symbol["asyncIterator"] === undefined) ((Symbol as any)["asyncIterator"]) = Symbol.for("asyncIterator");

Скомпилируйте и запустите как обычно.

Это также должно применяться в любых пакетах многократного использования - в идеале на первой строке main скрипта вашего модуля

Родная поддержка

Если вы нацеливаете узел 7 и выше, вы можете просто запустить асинхронные итераторы изначально с помощью флага.

Установите target: "esnext" в tsconfig.json, скомпилируйте и запустите с

node --harmony_async_iteration example.js

То же самое доступно и для ts-узла, где вы можете запускать его напрямую.

ts-node --harmony_async_iteration example.ts

С узлом 9; он был поставлен под флагом --harmony

С узла 10; он включен по умолчанию.

Предупреждение:

Я столкнулся с некоторыми проблемами с совместимостью, когда вы смешали скомпилированный код async-gen с машинописным текстом с помощью скомбинирования babel в пакете webpack. Это может быть связано с тем, как babel polyfill ищет символ, а затем создает его, если он отсутствует. Проблема совместимости заключается в том, что, по-видимому, код babel не считает, что код машинописного текста (+Symbol polyfill) имеет ключевую запись Symbol.asyncIterable.

Также можно избежать проблемы, используя тот же полиполк Symbol, который будет использовать плагин babel:

import "core-js/modules/es7.symbol.async-iterator"