TypeScript 2.8.3:类型必须有一个返回迭代器的Symbol.iterator方法。

140

我遇到了一个错误,提示说

Type must have a '[Symbol.iterator]()' method that returns an iterator.
它希望在划定的界限内:

它希望在划定的界限内:
class Test {
    private async do() {
        const done = [...(await this.test())]; // Here's the error
    }

    private async *test(): AsyncIterableIterator<string> {
        return;
    }
}

我在TypeScript GitHub存储库中发现了一些问题,但似乎没有帮助。它们都建议添加新的条目到lib中。我正在使用es6目标,并已经添加了esnextdomes2018。但这对错误没有任何影响。

我是否需要添加更多的lib条目(我怀疑这是不必要的,因为我使用的是包含所有内容的通用条目),还是我使用的代码无效?


3
看起来异步可迭代对象不支持扩展运算符:相关问题 - jcalz
9个回答

179
这对我有帮助。 在tsconfig中添加这个:
{
    "compilerOptions": {
        "lib": [
            "es5", "es6", "dom", "dom.iterable"
        ]
    }
}

这是为了让tsconfig在转译代码时知道要导入哪些接口。
dom.iterable包括这里提到的所有接口:https://github.com/microsoft/TypeScript/blob/main/src/lib/dom.iterable.d.ts 还要感谢@domlas提到这一点。我已经点赞了他的评论,以便将其视为默认原因。

4
@IlyaEremin https://github.com/microsoft/TypeScript/blob/master/lib/lib.dom.iterable.d.ts - domlas
2
@सत्यमेवजयते,我已经编辑了。感谢您的建设性评论。抱歉。 - Rohit Gupta
1
我必须添加 tsconfig.jsontsconfig.base.json,然后它才能正常工作。 - Santosh
由于ES5支持,"downlevelIteration": true也是必需的吗? - amirhe
3
你真的只需要 "dom", "dom.iterable",但它非常好用。 - JrBriones
显示剩余2条评论

34

如我在上面的评论中所述,扩展运算符目前不支持异步迭代器。相关的GitHub问题在tc39/proposal-async-iteration#103中。

从该问题中总结(除了像“你可以这样做,哎呀不行,没关系”之类的无关紧要的东西):

@jedwards1211说:

数组扩展运算符将来会成为此提案的一部分吗?

@domenic回答:

不是此提案的一部分...另一个提案可能会考虑在此处添加新功能。

我没有看到其他提案(想要开始一个吗?)。无论如何,由于它甚至不是JavaScript ESNext的一部分,因此很有可能不会被添加到TypeScript中。

最可行的选择是在@estus的回答中详细介绍的for await语法。非常抱歉我不能提供更多帮助。祝你好运!


28

我认为如果你将"this.test()"转换为字符串或数组,你就可以消除错误。

虽然我的情况不同,但我认为我的解决方案可能会帮助一些开发者。

我收到的错误信息是:

     Type 'Ingredient | Ingredient[]' must have a '[Symbol.iterator]()' 
     method that returns an iterator

enter image description here

我尝试了几种方法,以下三种方法都可以实现,并且第一个方法是最简单的:

enter image description here

enter image description here

enter image description here


1
这是最直接、相关且不偏袒他人的方式,让其他人能够找到有帮助的内容。谢谢! - Hugobop

17
当我们尝试使用展开语法(...)将对象解包到数组中时,会出现"Type Object must have a Symbol.iterator method that returns an iterator"的错误。要解决此错误,请将您的对象放入一个数组中或更正类型。
const obj = { name: 'James' };

// ⛔️ Error: Type Object must have a '[Symbol.iterator]()'
// method that returns an iterator.ts(2488)
const result = [...obj];

我们尝试使用扩展语法将对象的属性直接解析成数组。
这个问题的解决方案取决于你的使用情况。如果你想将对象解析成数组,请在使用扩展语法(...)之前用数组包装它。
 const obj = { name: 'James' };

const result = [...[obj]];

console.log(result); // ️ [{name: 'James'}]

2
这个评论帮助我意识到了我做错了什么。 - Илья Хоришко
一样。我不必要地将一个对象拆分到函数的参数中。对象的键已经与函数的单个参数匹配(该参数实际上是一个具有相同键的“选项”对象)。 - maninak

9
尽管语法上可能会有所暗示,但异步生成器函数并不是返回生成器的 async 函数。
正如该提案所述:

异步生成器函数类似于生成器函数,具有以下区别:

调用时,异步生成器函数返回一个对象,一个异步生成器,其方法(next、throw 和 return)返回 { value, done } 的承诺,而不是直接返回 { value, done }。这自动使返回的异步生成器对象成为异步迭代器。

它返回的是异步生成器,而不是承诺,因此使用await等待没有任何好处。
由于异步生成器具有 Symbol.asyncIterator 而不是 Symbol.iterator,所以它是非可迭代迭代器,即不能使用常规的 ES6 方法 (Array.from, for..of, spread 语法等) 进行迭代。这就是为什么要引入 for await..of 的原因。
以上代码应该是:
const values = [];

for await (const value of this.test()) {
  values.push(v);
}

异步迭代器的迭代方式与普通迭代器类似,唯一不同的是next()返回下一个值的promise,而不是值本身:

const iterator = this.test();
let next;
       
while ((next = await iterator.next()).done === false) {
  values.push(next.value);
}

自从异步生成器规范提出以来,ES6迭代方法中对于异步迭代器的支持可能会发生变化。

1
非常好的答案,谢谢。我知道for await,但不知道如何与扩展运算符一起使用,@jcalz解决了这个问题,所以我倾向于接受他们的答案,但是你的答案也很棒,我已经点赞了。 - Tomáš Hübelbauer

2

只需在您的扩展运算符上标记as any[],例如:

 addTemplateVariable(templateVariable: string) {
    this.patchState((state: CmsState) => ({
      cms: {
        ...state.cms,
        templateVariables: [
          ...state.cms.templateVariables as any[],
          templateVariable
        ]
      }
    }))
  }

在使用 ngrx 组件存储时,我遇到了这个问题


1
我在尝试迭代由async function*生成的值时遇到了这个错误。
从以下代码更改:
for (const value of myAsyncGeneratorFunction()) {

for await (const value of myAsyncGeneratorFunction()) {

修复了这个错误。


0

我在使用扩展语法(...)在一个 reducer(NgRx) 中时遇到了相同的错误,你可以看到以下内容:

const _ingresoEgresoReducer = createReducer(initialState, 
    on(setItems, (state, { items }) => ({ ...state,  items: [...items]})), 
    on(unSetItems, state => ({ ...state,  items: []})), 
);

它显示错误:“Type 'IngresoEgreso' 必须具有返回迭代器的 'Symbol.iterator' 方法。”与部分 [...items]。

为了解决这个问题,我应该改成

const _ingresoEgresoReducer = createReducer(initialState, 
    on(setItems, (state, { items }) => ({ ...state,  items: [...[items]]})), 
    on(unSetItems, state => ({ ...state,  items: []})), 
);

对我来说它很好用。

这个解决方案可以在https://bobbyhadz.com/blog/typescript-type-object-must-have-symbol-iterator-method找到。


-30

如果添加了错误

"strict": false

在tsconfig.json中


21
他们可能不想在未启用严格模式的情况下运行。 - GAntoine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接