我在 TypeScript 中遇到 IteratorResult 解构问题。我正在做一个简单的对象解构,但遇到了数组解构错误。
这是引发 TypeScript 错误的代码:
class ServiceLabelCollection extends ICollection<ServiceLabel> {
private collection: Collection<ServiceLabel>;
public addSoft(labels: ServiceLabel | Iterable<ServiceLabel>): this {
const isIterable = !(labels instanceof ServiceLabel);
const toAddIterable: Iterable<ServiceLabel> = isIterable ? labels : [labels];
const iterator: Iterator<ServiceLabel> = toAddIterable[Symbol.iterator]();
while (this.collection.size < ServiceLabelsCollection.maxSize) {
const { value, done }: IteratorResult<ServiceLabel> = iterator.next(); // Unsafe array destructuring of a tuple element with an `any` value. eslint@typescript-eslint/no-unsafe-assignment
if (done) break;
this.collection.addSoft(value);
}
return this;
}
}
这个问题似乎是一个错误,因为它是一个对象解构,而且我认为它实现得很好。我认为这可能是 TypeScript bug 的另一个原因是下一个代码没有给出错误:
class ServiceLabelCollection extends ICollection<ServiceLabel> {
private collection: Collection<ServiceLabel>;
public addSoft(labels: ServiceLabel | Iterable<ServiceLabel>): this {
const isIterable = !(labels instanceof ServiceLabel);
const toAddIterable: Iterable<ServiceLabel> = isIterable ? labels : [labels];
const iterator: Iterator<ServiceLabel> = toAddIterable[Symbol.iterator]();
while (this.collection.size < ServiceLabelsCollection.maxSize) {
const result: IteratorResult<ServiceLabel> = iterator.next(); // Simply I didn't do destructuring
if (result.done) break;
this.collection.addSoft(result.value);
}
return this;
}
}
有人看到我可能在这里犯的错误吗?或者其他人猜测这可能是 TypeScript 错误?
TLDR:不要手动输入所有内容。让打字稿推断事情是可以的。实际上,您在这里使用了错误的类型,导致类型被扩展为
any
,eslint 现在正在向您大喊大叫。
使用
值对元组元素进行不安全的数组解构。 eslint@typescript-eslint/无不安全分配any
这不是打字稿错误。这是一个 eslint 错误。而问题的根源在于
result.value
的类型是any
。解构只会导致 eslint 注意到这一点。
所以真正的问题是
result.value
被输入为 any
。让我们解决这个问题。
我已将您的代码简化为:
type ServiceLabel = { label: string }
const array: ServiceLabel[] = []
const iterator = array[Symbol.iterator]()
const { value, done }: IteratorResult<ServiceLabel> = iterator.next();
// ^ any
现在在您的 IDE(或打字稿游乐场)中,如果您将鼠标悬停在该片段中的迭代器结果上,您将看到此类型:
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>
请注意,未指定时第二个参数默认为
any
。然后请注意,您只传递了一个参数。
现在将鼠标悬停在
.next()
上,您将看到此类型:
Iterator<ServiceLabel, undefined, unknown>.next(...[value]: [] | [unknown]):
IteratorResult<ServiceLabel, undefined>
这表示
iterator.next()
返回此类型:
IteratorResult<ServiceLabel, undefined>
与您选择的类型不同。如果您将类型更改为
IteratorResult<ServiceLabel, undefined>
那么一切都应该按您的预期工作。
const { value, done }: IteratorResult<ServiceLabel, undefined> = iterator.next();
或者只是让它被推断,因为在打字稿中你不应该为每个值提供类型。
const { value, done } = iterator.next();
如果您深入了解
IteratorResult
的类型(cmd/ctrl+单击 IDE 中的类型),它会描绘出更大的图景:
interface IteratorYieldResult<TYield> {
done?: false;
value: TYield;
}
interface IteratorReturnResult<TReturn> {
done: true;
value: TReturn;
}
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
迭代器有两种返回值的方式。 “yield”结果是您通常期望迭代器迭代的结果,“return”结果是迭代器“完成”时的值。
在
ArrayIterator
的情况下,“yield”类型是数组成员的类型,“return”结果是 undefined
,因为当你到达数组末尾时,没有剩余的项目可以返回.
但是如果您手动使用
IteratorResult
类型,则必须提供两种类型以避免 any
,因为 TReturn
类型默认为 any
。这炸毁了这种联合类型:
IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
// ends up this: IteratorYieldResult<T> | IteratorReturnResult<any>;
因为任何与
any
的并集都是 any. e.g.
,类型 A = number |任何 // 任何`.