这其实是一个非常复杂的问题。我并不假装完全理解它。但也许我可以提供一些见解。
他们为什么要添加它们?
(in 这次提交 https://github.com/microsoft/TypeScript/commit/e8bf9584aa74aabfecb51a02edb13e3657508274#diff-5c3d60d8ed16d2857e28a35a61302b48)。
Typescript 决定,无论好坏,它都希望对生成器进行更严格的类型检查。这实际上是有一些正当理由的。举下面的例子
function* foo() {
let m = 0;
while (m < 10) {
yield m++;
}
return "done";
}
let gen = foo(),
curr;
while(!(curr = gen.next()).done) {}
// At his point we should know that
// curr.value is a string because curr.done is true
在这里我们可以看到问题——我们无法知道是否按照我们应该的所有逻辑规则返回或产生了一个值。所以他们推出了TReturn。接下来是介绍 https://github.com/microsoft/TypeScript/pull/30790 to:
[…]正确检查结果并提供类型yield
基于生成器返回类型注释的下一个类型的表达式(即TNext
输入Generator
定义如上)。
为什么是默认值?
现在,如果您决定进行此类更改,您可能会破坏一些代码 - 目标是尽可能少地破坏。
我们必须注意,在使用中存在惯用差异next()
生成器和非生成器迭代器中的函数。作为ECMA-262 备注 https://tc39.es/ecma262/#sec-iterator-interface对于迭代器。
参数可以传递给next
函数,但它们的解释和有效性取决于目标迭代器。 for-of 语句和迭代器的其他常见用户不传递任何参数,因此希望以这种方式使用的迭代器对象必须准备好处理不带参数的调用。
迭代器主要用在 for-of 循环中,不向 next 传递参数。事实上,将参数传递给下一个函数的情况非常罕见(MDN 甚至称其为“零参数函数”)。因此,默认值的唯一明智选择TNext
将会undefined
。进行中unknown
将是类型检查的一个很大的障碍(更不用说用--strictNullChecks
).
如果将一个参数传递给next()
带有生成器的函数并不是一种很常见的做法 - 它实际上有一个有效的用例......并且定义了行为标准 https://tc39.es/ecma262/#sec-generator.prototype.next:
生成器.prototype.next(value)
The next
方法执行以下步骤:
- Let g be the this value.
- 返回?GeneratorResume(g, value, 空的)。
and in MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next:
要发送到生成器的值。
该值将被分配为yield
表达。例如,在variable = yield expression
,传递给的值.next()
函数将被分配给variable
.
更不用说,在典型的用例中,第一个.next()
call 将在没有参数的情况下调用,后续的调用将带有参数。不幸的是,没有办法指定“可选的第一次,未知的后续时间”类型,所以我想鉴于这一切,他们解决了unknown
为了TNext
在发电机中。
当然,没有完美的情况。但他们必须满足于他们认为问题最少的做法。
所有这些问题都在这个问题 https://github.com/Microsoft/TypeScript/issues/2983对于任何有兴趣的人。