如何正确使用AsyncIterator?解决for await...of报错问题
问题核心
for await...of语法要求迭代对象必须实现**AsyncIterable接口**——也就是对象要有[Symbol.asyncIterator]()方法,返回一个AsyncIterator。你当前的接口定义tables()返回的是AsyncIterator<Table>,虽然你的async generator函数实际返回的是同时实现了AsyncIterator和AsyncIterable的AsyncIterableIterator,但TypeScript会严格按照接口定义做类型检查,因此报错。
修改方案
1. 修正接口定义
把IDriver接口中tables()的返回类型从AsyncIterator<Table>改为AsyncIterableIterator<Table>(或更简洁的AsyncIterable<Table>,因为AsyncIterableIterator继承了AsyncIterable):
export interface IDriver { tables(): AsyncIterableIterator<Table>; // 或者写成:tables(): AsyncIterable<Table>; }
2. 实现类无需额外修改
你的MySql类中async *tables()是async generator函数,它的返回类型天然就是AsyncIterableIterator<Table>,完全符合修改后的接口要求,所以实现代码可以保持不变:
export class MySql implements IDriver { async *tables(): AsyncIterableIterator<Table> { // 这里的返回类型也可以省略,TS会自动推断 const sql = `select table_name, table_type, table_rows from information_schema.tables where table_schema = ${this.schema} order by table_name;` const rows = await this.query<{ table_name: string table_type: string table_rows: number }>(sql) for (const row of rows) { yield { name: row.table_name, rows: row.table_rows, type: row.table_type } as Table } } }
3. 兼容方案(无需修改接口)
如果因为某些原因不能修改接口,可以手动把AsyncIterator包装成AsyncIterable再使用:
const tableIterator = mysql.tables(); const tableIterable = { [Symbol.asyncIterator]() { return tableIterator; } }; for await (const it of tableIterable) { print(it); }
为什么不需要core-js
你提到的旧方案(引入core-js/shim)是针对早期JS环境不支持AsyncIterable的情况,而TypeScript 5.5+已经完全支持现代ES语法,你的tsconfig.json也配置了target: ESNext和lib: ["ES2018.AsyncIterable"],所以问题本质是类型定义不匹配,而非环境缺失。
内容的提问来源于stack exchange,提问作者Simple Fellow

