Photo by PJH on Unsplash

On this page

For runtime behavior—async function*, for await..of, and the async iterator protocol—see Async iterators and for await..of.

TypeScript adds static types on top of JavaScript async generators. Values yielded, values passed back into yield, and the final return type can each be described separately.

AsyncGenerator yield, return, and next

AsyncGenerator<TYield, TReturn, TNext> parameterizes:

  • TYield — type of values produced by yield
  • TReturn — type passed to return() (defaults to void)
  • TNext — type of argument sent into next() (defaults to unknown)
type Person = { name: string; title: string };
async function* getItems(
items: Person[],
): AsyncGenerator<Person, void, unknown> {
for (const item of items) {
await new Promise((r) => setTimeout(r, 100));
yield item;
}
}

Typing for await..of consumers

Parameters typed as AsyncIterable<T> accept async generators, readable streams (where typings allow), and custom [Symbol.asyncIterator]() implementations:

async function renderOverTime(source: AsyncIterable<Person>) {
for await (const item of source) {
console.log(`${item.name} ${new Date().toLocaleTimeString()}`);
}
}
await renderOverTime(getItems([{ name: "Ada", title: "Engineer" }]));

Use AsyncIterator<T, TReturn, TNext> when you hold the iterator object and call next() manually.

Inference and explicit annotations

TypeScript usually infers AsyncGenerator from async function* bodies. Annotate the return type when you implement an interface or export a public API surface:

interface LineSource {
lines(): AsyncGenerator<string>;
}
class FileLines implements LineSource {
async *lines() {
yield "first";
}
}

If yield types widen unexpectedly, add an explicit return type on the generator function or type the yield expression.

Strictness and Promise results

Each next() on an async iterator returns Promise<IteratorResult<TYield, TReturn>>. Under strict, handle done: true before using value:

async function first<T>(it: AsyncIterator<T>): Promise<T | undefined> {
const { done, value } = await it.next();
return done ? undefined : value;
}

Rejected promises from the iterator propagate to the await on next() or to for await..of—same as ordinary async functions.

Search articles

Type a word to search published articles.

Open the search page