首页 / TypeScript 入门教程 / 迭代器与生成器

TypeScript 入门教程

迭代器与生成器

本教程共 80 篇 · 第 72 篇 · 更新于 2026-08-10 · 约 14 分钟阅读

TypeScriptTypeScript 入门教程迭代器生成器IteratorGeneratorSymbol.iterator

本节目标:搞懂 TypeScript 世界里的”可迭代”是什么意思——Iterable 和 Iterator 接口长什么样、for..of 的类型推断有多聪明、生成器函数的三个泛型参数到底是干嘛的。

可迭代协议:Iterable 与 Iterator

ES2015 引入了一套”可迭代协议”——一个对象只要实现了 Symbol.iterator 方法,就能被 for..of 遍历。TypeScript 为这套协议提供了完整的类型定义:

// TypeScript 内置的迭代器接口(简化版)
interface Iterator<T> {
  next(): IteratorResult<T>;
}

interface IteratorResult<T> {
  done: boolean;
  value: T;
}

interface Iterable<T> {
  [Symbol.iterator](): Iterator<T>;
}

简单说:Iterable 是”可被迭代的容器”,Iterator 是”正在迭代的游标”。数组、Map、Set、字符串都内置了 Symbol.iterator 方法,所以它们都是 Iterable。

const arr = [1, 2, 3];
const it = arr[Symbol.iterator]();

console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

TypeScript 能完美推断 it 的类型为 Iterator<number>next() 返回 IteratorResult<number>

for..of 的类型推断

当你在 TypeScript 里写 for..of,编译器会根据 Iterable 的泛型参数自动推断循环变量的类型:

const names = ["Alice", "Bob", "Charlie"];

for (const name of names) {
  // name 被推断为 string,不需要手动标注
  console.log(name.toUpperCase());
}

Map 和 Set 的推断同样精准:

const map = new Map<string, number>();
map.set("a", 1);
map.set("b", 2);

for (const [key, value] of map) {
  // key 推断为 string,value 推断为 number
  console.log(`${key}: ${value}`);
}

const set = new Set([10, 20, 30]);
for (const num of set) {
  // num 推断为 number
  console.log(num * 2);
}
Tip

想让你的自定义类支持 for..of?实现 [Symbol.iterator]() 方法就行,TypeScript 会自动识别。

自定义可迭代对象

直接实现 Iterable<T> 接口:

class Range implements Iterable<number> {
  constructor(private start: number, private end: number) {}

  [Symbol.iterator](): Iterator<number> {
    let current = this.start;
    const end = this.end;

    return {
      next(): IteratorResult<number> {
        if (current <= end) {
          return { value: current++, done: false };
        }
        return { value: undefined as any, done: true };
      },
    };
  }
}

const range = new Range(1, 5);
for (const n of range) {
  console.log(n); // 1, 2, 3, 4, 5
}

class Range implements Iterable<number> 告诉 TS:“这个类的实例可以被迭代,每次迭代产生 number”。如果你漏写了 next() 方法,TS 会报错,因为 Iterator<number> 要求返回 IteratorResult<number>

生成器函数

生成器(Generator)是创建迭代器的最简方式。用 function* 声明,yield 暂停执行:

function* simpleGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const gen = simpleGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }

TypeScript 会自动推断生成器的返回类型。上例中 gen 的类型是 Generator<number, void, unknown>

Generator 的三个泛型参数

生成器函数的类型签名是 Generator<T, TReturn, TNext>

参数含义对应什么
Tyield 产生的值的类型next() 返回的 value
TReturnreturn 返回的最终结果类型最后 { done: true, value: ... }value
TNext通过 next(x) 传入的值类型yield 表达式的返回值类型

大多数时候你只关心第一个参数:

function* numberGenerator(): Generator<number> {
  yield 1;
  yield 2;
  yield 3;
}

Generator<number> 等价于 Generator<number, void, unknown>TReturnTNext 用了默认值。

TReturn:return 的最终值

生成器可以用 return 提前结束,返回的值会在 done: true 时作为 value

function* genWithReturn(): Generator<number, string> {
  yield 1;
  yield 2;
  return "done";
}

const g = genWithReturn();
console.log(g.next()); // { value: 1, done: false }
console.log(g.next()); // { value: 2, done: false }
console.log(g.next()); // { value: "done", done: true }
//          ↑ 注意:final value 是 string,不是 number

如果没有显式 returnTReturn 默认是 void。迭代到最后 done: truevalueundefined

TNext:向生成器”塞值”

你可以通过 next(x) 向生成器内部传值,yield 表达式会收到这个值:

function* accumulator(): Generator<number, void, number> {
  let sum = 0;
  // 第一个 next() 传入的值会被忽略(启动时还没有暂停点)
  const add1: number = (yield sum) as number;
  sum += add1;
  const add2: number = (yield sum) as number;
  sum += add2;
  yield sum;
}

const acc = accumulator();
console.log(acc.next());     // { value: 0, done: false } —— 启动,走到第一个 yield
console.log(acc.next(5));    // { value: 5, done: false } —— sum += 5
console.log(acc.next(3));    // { value: 8, done: false } —— sum += 3
console.log(acc.next());     // { value: undefined, done: true }
Note

第一次 next() 不能传值(或者传了也会被忽略),因为生成器还没执行到任何 yield 暂停点。这是 JS 的运行时行为,TS 类型系统没法强制检查这一点。

生成器作为 Iterable

生成器返回的对象同时实现了 Iterable 接口,所以可以直接用在 for..of 里:

function* alphabet() {
  yield "a";
  yield "b";
  yield "c";
}

for (const letter of alphabet()) {
  console.log(letter); // "a", "b", "c"
}

TypeScript 推断 letterstring,来自生成器的 T 参数。

yield* 委托给另一个迭代器

yield* 把迭代委托给另一个 Iterable 对象:

function* combined() {
  yield* [1, 2, 3];
  yield* new Set(["a", "b"]);
}

for (const item of combined()) {
  // item 的类型推断为 number | string
  console.log(item);
}

注意 TS 的推断:它把两个 yield* 的产出类型合并成联合类型 number | string

如果你明确标注返回类型,可以用更精确的类型:

function* numbered(): Generator<number | string> {
  yield* [1, 2, 3];
  yield* ["a", "b", "c"];
}

异步生成器

async function* 创建的异步生成器,用 for await..of 遍历:

async function* asyncNumbers() {
  for (let i = 0; i < 3; i++) {
    await new Promise((r) => setTimeout(r, 100));
    yield i;
  }
}

const asyncGen = asyncNumbers();
// asyncGen 的类型是 AsyncGenerator<number, void, unknown>

(async () => {
  for await (const num of asyncGen) {
    console.log(num); // 0, 1, 2,每次间隔 100ms
  }
})();

AsyncGeneratorGenerator 的区别:next() 返回 Promise<IteratorResult<T>> 而非直接返回 IteratorResult<T>

小结

  • 实现 Symbol.iterator 的对象是 Iterable,可以被 for..of 遍历
  • for..of 的循环变量类型自动从 Iterable 推断,不需要手写
  • 生成器函数 function* 返回 Generator<T, TReturn, TNext> 对象
  • T 是 yield 产生的值类型,TReturn 是 return 的最终值类型,TNextnext(x) 传入值的类型
  • 生成器同时实现了 Iterable,直接用 for..of 即可
  • 异步生成器用 async function* + for await..of,返回 AsyncGenerator<T, TReturn, TNext>