TypeScript 2.8.3 Type 必须具有一个 Symbol.iterator 方法,该方法返回一个迭代器

我遇到了一个错误

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条目(我怀疑我使用的是包含所有内容的 catchall 条目)或者我使用的代码是无效的?

184859 次浏览

Despite what the syntax may suggest, async generator function isn't async function that returns a generator.

As the proposal states,

Async generator functions are similar to generator functions, with the following differences:

When called, async generator functions return an object, an async generator whose methods (next, throw, and return) return promises for { value, done }, instead of directly returning { value, done }. This automatically makes the returned async generator objects async iterators.

It returns asynchronous generator, not a promise, so awaiting it doesn't make any good.

Since asynchronous generator has Symbol.asyncIterator instead of Symbol.iterator, it's non-iterable iterator, i.e. it cannot be iterated with regular ES6 methods (Array.from, for..of, spread syntax, etc). This is the reason why for await..of was introduced.

The code above should be:

const values = [];


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

The iteration over asynchronous iterator can be desugared similarly to regular iterators, the difference is that next() returns a promise of next value, not a value itself:

const iterator = this.test();
let next;
       

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

Since asynchronous generator spec is a proposal, the support for async iterators in ES6 iteration methods may be subject to change.

As I commented above, the spread operator is unfortunately currently unsupported for asynchronous iterators. The relevant issue in GitHub is tc39/proposal-async-iteration#103.

Recap from that issue (minus extraneous stuff such as "you could do it this way, oops no you can't, never mind"):

@jedwards1211 said:

Will array spread operator support ever be part of this proposal?

@domenic ansered:

Not part of this proposal... Another proposal could certainly contemplate something new here.

And I don't see a proposal elsewhere (want to start one?). In any case, since it isn't part of even JavaScript ESNext, it most likely won't get added to TypeScript.

The most viable alternative is the for await syntax detailed in @estus's answer. Sorry I couldn't be more helpful. Good luck!

this has helped me. in tsconfig, add this :

{
"compilerOptions": {
"lib": [
"es5", "es6", "dom", "dom.iterable"
]
}
}

This is required for tsconfig to know which interfaces to import while transpiling your code.

dom.iterable includes all the interfaces mentioned here : https://github.com/microsoft/TypeScript/blob/master/lib/lib.dom.iterable.d.ts

Also thanks to @domlas for mentioning this. I already upvoted his comment so that it is treated as default reason.

Error went if added

"strict": false

in tsconfig.json

I had the same error trying to use the spread syntax (...) in a reducer(NgRx), you can see the following:

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

It shows the error "Type 'IngresoEgreso' must have a 'Symbol.iterator' method that returns an iterator." with the part [...items]

To solve the issue I should change to

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

And it works fine to me.

This solution was found at https://bobbyhadz.com/blog/typescript-type-object-must-have-symbol-iterator-method

Simply tag as any[] to your spread operator e.g.

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

I came across this problem when using ngrx component store

I think you can get rid of the error if you cast "this.test()" to string or array.

My situation was different, but I think my solutions might help some fellow developers.

The error message I got was:

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

enter image description here

I tried a few ways, and the following THREE worked, with the FIRST one as the simplest:

enter image description here

enter image description here

enter image description here

The error "Type Object must have a Symbol.iterator method that returns an iterator" occurs when we try to use the spread syntax (...) to unpack an object in an array. To solve the error, wrap your object in an array or correct your typings.

like this..

const obj = { name: 'James' };


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

We tried to use the spread syntax to unpack the properties of an object directly into an array.

The solution for this depends on your use case. If you want to unpack the object into an array, wrap it in an array before using the spread syntax (...).

 const obj = { name: 'James' };


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


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