Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript: async generator

I'd like to have a function like this:

export async function* iterateDir(dir: string) {
    let list = await fs.readdir(dir); // fs-promise implementation of readdir
    for (let file of list) {
        yield file;
    }
}

Which I would use like:

for (let file in iterateDir(dir)) {
    processFile(file);
}

This doesn't work because a function cannot be both async and a generator.

How would I structure the code to achieve the same?

  1. If I change the await fs.readdir to callbacks, I assume the outer for..of loop would not wait.
  2. If I get rid of the generator and the directory is huge, iterateDir() will be slow.

For reference: async generator function proposal

like image 245
Borek Bernard Avatar asked Nov 03 '16 16:11

Borek Bernard


People also ask

What is async generator?

Async generator functions behave similarly to generator functions: the generator function returns an object that has a next() function, and calling next() executes the generator function until the next yield . The difference is that an async iterator's next() function returns a promise.

How do I iterate through async generator?

The syntax is simple: prepend function* with async . That makes the generator asynchronous. And then use for await (...) to iterate over it, like this: async function* generateSequence(start, end) { for (let i = start; i <= end; i++) { // Wow, can use await!

Does TypeScript have async await?

Async - Await has been supported by TypeScript since version 1.7. Asynchronous functions are prefixed with the async keyword; await suspends the execution until an asynchronous function return promise is fulfilled and unwraps the value from the Promise returned.

What is IterableIterator?

It's explained in detail here: " IterableIterator is an interface defined by TypeScript that combines the contracts of Iterables and Iterator into one. This is because, in some cases, it makes sense to have the Iterable as an Iterator itself, removing the need to have an external class that serves as the iterator."


1 Answers

This is supported in TypeScript 2.3 - tracked issue

It introduces a few new types, notably:

interface AsyncIterable<T> {
    [Symbol.asyncIterator](): AsyncIterator<T>;
}

but most importantly it also introduces for await ... of

for await (const line of readLines(filePath)) {
  console.log(line);
}

where

async function* readLines(path) {
   //await and yield ...
}

Be aware that if you want to try this you will need to configure typescript to let it know you have run-time support (add "esnext.asynciterable" to lib list) you will probably need to polyfill Symbol.asyncIterator. see TS2318: Cannot find global type 'AsyncIterableIterator' - async generator

like image 74
Meirion Hughes Avatar answered Oct 17 '22 07:10

Meirion Hughes