Перейти к основному содержимому

Генераторы и итераторы в TypeScript

Разработчику

Дальше: Асинхронность · Дженерики · Циклы


Генераторы (function*) возвращают ленивую последовательность через yield. TypeScript типизирует их как Generator<T> и AsyncGenerator<T>. Полезно для потоков данных, пагинации и обхода без загрузки всего массива в память. Удобный порядок — циклы, асинхронность, эта статья.

Runtime и протокол итерации — итераторы в JavaScript, циклы в TypeScript.


Generator<T>

function* range(from: number, to: number): Generator<number> {
for (let i = from; i <= to; i += 1) {
yield i;
}
}

for (const n of range(1, 3)) {
console.log(n);
}

Разбор:

  • function* возвращает итерируемый объект с методом next().
  • Тип yield — number; return type генератора — Generator<number, void, unknown> (третий параметр — тип yield*).

Явный тип возврата

function* ids(): Generator<string, void, undefined> {
let n = 0;
while (true) {
yield `id-${n += 1}`;
}
}

Iterable и Symbol.iterator

class Counter implements Iterable<number> {
constructor(private readonly max: number) {}

*[Symbol.iterator](): Generator<number> {
for (let i = 1; i <= this.max; i += 1) {
yield i;
}
}
}

for (const n of new Counter(3)) {
console.log(n);
}

Разбор:

  • for...of вызывает Symbol.iterator.
  • Можно реализовать итератор вручную (next(): IteratorResult<T>), генератор проще.

Делегирование — yield*

function* concat(
a: Iterable<number>,
b: Iterable<number>,
): Generator<number> {
yield* a;
yield* b;
}

Разбор:

  • yield* перебирает другую последовательность.

AsyncGenerator и for await...of

Код ITЗагрузка примера кода…

Разбор:


Типизация next и ранний выход

function* gen(): Generator<number> {
yield 1;
yield 2;
return 99;
}

const g = gen();
console.log(g.next()); // { value: 1, done: false }
console.log(g.return(0)); // завершение

Разбор:

  • return в генераторе даёт { done: true, value: 99 }.
  • В прикладном коде чаще используют break в for...of.

Когда использовать

СценарийПодход
Ленивый обход большого спискаfunction*
Пагинация APIasync function*
Простой массивfor...of / mapКоллекции и массивы в TypeScript
RxJS-потокиObservable (вне TS core)

Частые ошибки

ОшибкаЧто делать
Забыли * в function*синтаксическая ошибка
Путаница Generator и Iterableреализуйте Symbol.iterator
Бесконечный генератор без breakусловие выхода
for...of на async genтолько for await...of

Практика

  1. Напишите range(from, to): Generator<number>.
  2. Реализуйте Counter как Iterable.
  3. Сделайте async function* с тремя страницами mock API.
  4. Сравните память: [...range(1, 1_000_000)] и цикл с break на 100.
  5. Типизируйте возврат генератора явно.

Смежные статьи