Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TS2318: Cannot find global type 'AsyncIterableIterator' - async generator

I have an async generator:

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();

but with typescript 2.3 this give me errors:

error TS2318: Cannot find global type 'AsyncIterableIterator'. example.ts(10,26):

error TS2504: Type must have a 'Symbol.asyncIterator' method that returns an async iterator.

How can this error be fixed and how can you run the async generator?

like image 271
Meirion Hughes Avatar asked Apr 29 '17 10:04

Meirion Hughes


1 Answers

Symbol.asyncIterator is an esnext feature; so you must explicitly target esnext, or add the esnext.asynciterable library, for typescript to support the syntax. However, typescript does not deal with the implementation of Symbols at runtime at present, so you need to polyfill.

Polyfill + Down-Compile

Add "esnext.asynciterable" to lib in tsconfig.json

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

you can polyfill Symbol.asyncIterator by simply creating a new Symbol before you do anything else.

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

Compile and run as normal.

This should also be applied in any reusable packages - ideally on the very first line of your module's main script

Native Support

If you are targetting node 7 and above, you can actually just run async iterators natively with a flag.

Set target: "esnext" in tsconfig.json, compile, and run with

node --harmony_async_iteration example.js

Same is available for ts-node too, where you can run it directly.

ts-node --harmony_async_iteration example.ts

With Node 9; it has been staged under the --harmony flag

As of Node 10; it is enabled by default.

Warning:

I've experienced some compatibility issues when you mix typescript compiled async-gen code with babel's down-compile in a webpack bundle. It may be due how babel's polyfill looks for the symbol and then creates one if it is missing. The compatibility issue is that it would appear the babel code doesn't think the typescript (+Symbol polyfill) code has a Symbol.asyncIterable key-entry.

Could also avoid the problem by using the same Symbol polyfill that babel's plugin will use:

import "core-js/modules/es7.symbol.async-iterator"
like image 155
Meirion Hughes Avatar answered Nov 08 '22 23:11

Meirion Hughes