You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TS1163:TypeScript为何禁止在函数内部使用yield?

为什么TypeScript不允许在普通函数内部使用yield?

首先要明确:这个限制并非TypeScript独创,它完全对齐了ECMAScript(ES)标准的规定——yield只能在生成器函数(带function*或async function*声明的函数)内部使用。背后的原因既有技术实现上的硬限制,也有语言设计层面的优先级考量:

一、技术层面的核心障碍

生成器函数和普通函数的执行模型本质不同:

  • 普通函数是一次性执行到底的,遵循常规的调用栈逻辑,执行过程中无法被暂停和恢复,也不需要保存执行状态。
  • 生成器函数会被编译成状态机结构,yield的作用是暂停当前生成器的执行、保存上下文状态,等待后续调用next()时恢复执行。

如果允许在普通函数(比如forEach的回调、异步API的回调)里使用yield,会遇到无法解决的上下文问题:

  1. 调用栈分离:普通函数的调用栈和外层生成器的栈是独立的。比如array.forEach的回调由forEach内部同步调用,它的执行是独立于外层生成器的,没法把yield的暂停/恢复逻辑绑定到外层生成器的状态机上。
  2. 异步上下文丢失:在async*生成器的异步回调(比如你提到的pollX回调)中,回调执行时外层生成器可能已经处于暂停状态,此时回调里的yield找不到对应的生成器上下文,会导致状态混乱、执行流程不可控。

这些问题不是编译器“不想解决”,而是当前JS/TS的执行模型下,无法在不破坏现有语言逻辑的前提下实现跨函数的yield绑定。

二、语言设计的优先级选择

  1. 遵循ES标准:TypeScript的核心目标是扩展而非颠覆ES标准,既然ES规范明确限制了yield的使用范围,TS自然不会单独突破这个限制。
  2. 复杂度与收益不对等:要支持跨普通函数的yield,需要大幅增加语言的复杂度——比如要处理闭包状态追踪、跨作用域的上下文绑定、异步回调中的状态同步等。而实际开发中,绝大多数场景都可以通过替代方案解决:
    • 像forEach回调用yield的问题,换成for循环就能解决,因为for循环是在生成器函数的直接作用域内,yield能直接绑定到当前生成器。
    • 对于无法修改的pollX异步回调,可以先收集所有回调的结果,再统一在外层生成器中yield,或者用Promise结合迭代器的方式重构流程。

由于这种场景的需求相对小众,且替代方案成本不高,TC39(ES标准委员会)和TypeScript团队都没有把这个特性列为高优先级开发项。

内容的提问来源于stack exchange,提问作者Tobi Akinyemi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 15:07:26