TypeScript 中的 yield 和 Generator 使用指南

一、引言

在 JavaScript 中,Generator 是一种强大的函数形式,允许函数在执行过程中"暂停"和"恢复"。而在 TypeScript 中,Generator 同样受支持,并且拥有完整的类型推导与定义能力,使得开发者可以更安全、更清晰地使用这一特性。

本篇文章将系统总结 TypeScript 中如何使用 yield 与 Generator,包括语法、类型定义、应用场景和注意事项。


二、什么是 Generator?

Generator 函数是一种可以 中断执行并返回多个值 的函数。它以 function* 的形式声明,通过 yield 表达式逐步"产出"值。

ts 复制代码
function* simpleGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

调用 simpleGenerator() 并不会立即执行函数体,而是返回一个 Iterator 对象,通过调用其 .next() 方法,逐步获得每一个 yield 的值。

ts 复制代码
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 中使用 Generator

3.1 基本类型定义

TypeScript 可以对 Generator 的返回值、输入值、return 结果进行严格的类型定义:

ts 复制代码
function* gen(): Generator<number, string, unknown> {
  yield 1;
  yield 2;
  return "done";
}

上面的泛型参数含义如下:

ts 复制代码
Generator<YieldType, ReturnType, NextType>
  • YieldType: 每次 yield 返回的值类型
  • ReturnType: 函数通过 return 最终返回的值类型
  • NextType: 外部传入 .next(value) 的值类型

3.2 接收外部输入

你可以在 Generator 中通过 yield 表达式接收 .next() 传入的值:

ts 复制代码
function* adder(): Generator<string, number, number> {
  const a = yield "Please provide a number";
  const b = yield "Another number please";
  return a + b;
}

const g = adder();
console.log(g.next());        // { value: "Please provide a number", done: false }
console.log(g.next(10));      // { value: "Another number please", done: false }
console.log(g.next(20));      // { value: 30, done: true }

四、Generator 的应用场景

4.1 惰性计算(Lazy Evaluation)

ts 复制代码
function* infiniteCounter(): Generator<number> {
  let i = 0;
  while (true) {
    yield i++;
  }
}

适用于需要按需计算而不是一次性生成的场景,比如大数据分页、日志流等。

4.2 数据流处理

ts 复制代码
function* dataStream(data: string[]): Generator<string> {
  for (const item of data) {
    yield item.toUpperCase();
  }
}

可以与 for...of 搭配,实现流式数据处理。

4.3 协程式异步控制(传统用法)

虽然现代 JavaScript 推荐使用 async/await,但 Generator 曾用于模拟协程控制流(如 co 库):

ts 复制代码
function* flow() {
  const result1 = yield fetch("/api/data1");
  const result2 = yield fetch(`/api/data2?id=${result1.id}`);
  return result2;
}

五、Generator 与 Iterable 协议

Generator 本身实现了 Iterable 接口,因此可以直接用于 for...of 循环:

ts 复制代码
function* countdown(n: number) {
  while (n > 0) {
    yield n--;
  }
}

for (const i of countdown(3)) {
  console.log(i); // 3, 2, 1
}

也可以使用展开运算符:

ts 复制代码
console.log([...countdown(3)]); // [3, 2, 1]

六、与异步 Generator 的对比(简要)

TypeScript 同样支持 async function* 来创建异步 Generator:

ts 复制代码
async function* asyncGen(): AsyncGenerator<number> {
  for (let i = 0; i < 3; i++) {
    await new Promise(res => setTimeout(res, 100));
    yield i;
  }
}

(async () => {
  for await (const n of asyncGen()) {
    console.log(n);
  }
})();

区别:

  • yield 可用于同步 Generator;
  • await yield 可用于异步 Generator。

七、注意事项

  • yield 不能在普通函数中使用,只能在 function* 中使用;
  • 不同于 returnyield 不会结束函数;
  • 每次调用 .next() 会推进函数执行到下一个 yield
  • Generator 不适合复杂异步逻辑处理(推荐使用 async/await)。

八、总结

功能点 是否支持 说明
function* 创建一个 Generator 函数
yield 用于返回值,并暂停函数执行
.next(value) 继续执行函数,并传值进来
类型定义 Generator 泛型支持三类类型
异步 Generator 支持 async function*

在 TypeScript 中使用 Generator,可以帮助你实现更加清晰的迭代逻辑和惰性计算模型,尤其在处理数据流、实现中间状态管理等场景时,具有独特的优势。

相关推荐
董先生_ad986ad7 分钟前
C# 解析 URL URI 中的参数
前端·c#
江城开朗的豌豆20 分钟前
Vue中Token存储那点事儿:从localStorage到内存的避坑指南
前端·javascript·vue.js
江城开朗的豌豆21 分钟前
MVVM框架:让前端开发像搭积木一样简单!
前端·javascript·vue.js
氢灵子31 分钟前
Canvas 变换和离屏 Canvas 变换
前端·javascript·canvas
GISer_Jing37 分钟前
Axios面试常见问题详解
前端·javascript·面试
库库林_沙琪马40 分钟前
深入理解 @JsonGetter:精准掌控前端返回数据格式!
java·前端
CRPER1 小时前
告别繁琐配置:一个现代化的 TypeScript 库开发模板,让你高效启动项目!
前端·typescript·node.js
Embrace1 小时前
NextAuth实现Google登录报错问题
前端
小海编码日记1 小时前
Geadle,Gradle插件,Android Studio and sdk版本对应关系
前端
粤M温同学1 小时前
Web前端基础之HTML
前端·html