我正在尝试定义一个 AsycIterator 并使用它。定义作品但使用它一直是一个问题。这是我的代码,请注意与问题无关的其他代码已被删除
这就是我定义迭代器的方式
export interface IDriver {
tables(): AsyncIterator<Table>
// code removed
}
这就是我的实现方式。
export class MySql implements IDriver {
async *tables(): AsyncIterator<Table> {
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
}
}
// ---
}
这是我的 package.json 文件
{
"compilerOptions": {
"target": "ESNext" ,
"lib": [
"ES2018.AsyncIterable",
"DOM",
"ESNext"
] ,
"jsx": "preserve" ,
"experimentalDecorators": true ,
"emitDecoratorMetadata": true ,
"useDefineForClassFields": true ,
"moduleDetection": "auto" ,
"module": "NodeNext",
"rootDir": "src/" ,
"moduleResolution": "NodeNext" ,
"allowUmdGlobalAccess": true ,
"resolvePackageJsonExports": true ,
"resolvePackageJsonImports": true ,
"resolveJsonModule": true ,
"checkJs": true ,
"declaration": true ,
"declarationMap": true ,
"sourceMap": true ,
"outDir": "./build" ,
"removeComments": true ,
"newLine": "crlf" ,
"stripInternal": true ,
"preserveConstEnums": true ,
"allowSyntheticDefaultImports": true ,
"esModuleInterop": true ,
"forceConsistentCasingInFileNames": true ,
"strict": true ,
"noImplicitAny": true ,
"strictNullChecks": true ,
"strictFunctionTypes": true ,
"strictBindCallApply": true ,
"strictPropertyInitialization": true ,
"noImplicitThis": true ,
"useUnknownInCatchVariables": true ,
"alwaysStrict": true ,
"noUnusedLocals": true ,
"noUnusedParameters": true ,
"exactOptionalPropertyTypes": true ,
"noImplicitReturns": true ,
"noFallthroughCasesInSwitch": true ,
"noUncheckedIndexedAccess": true ,
"noImplicitOverride": true ,
"noPropertyAccessFromIndexSignature": true ,
"skipLibCheck": true ,
},
"include": ["./src/*"]
}
这就是上面函数的用法
for await (const it of mysql.tables()) {
print(it)
}
这给了我一个错误
src/main.ts:13:26 - 错误 TS2504:类型“AsyncIterator
”必须具有返回的 [Symbol.asyncIterator] () 方法 异步迭代器。
如果我尝试探索它,这就是我在类型定义中找到的内容:
interface AsyncIterable<T> {
[Symbol.asyncIterator](): AsyncIterator<T>;
}
interface SymbolConstructor {
/**
* A method that returns the default async iterator for an object. Called by the semantics of
* the for-await-of statement.
*/
readonly asyncIterator: unique symbol;
}
declare var Symbol: SymbolConstructor;
我也尝试过这里给出的解决方案:
异步迭代器如何工作?错误 TS2504:类型必须具有返回异步迭代器的“[Symbol.asyncIterator]()”方法
这是一个 6 年前的问题,对我来说根本不起作用。 core-js/shim 没有效果。我不知道该解决方案是否仅对特定版本的打字稿有效。我使用的是5.5.4版本。下面给出了我能够使用 AsyncIterator 的唯一方法。
const rows = await mysql.tables()
let item = await rows.next()
while (!item.done) {
item = await rows.next()
}
这显然是一种奇怪的使用 AsyncIterator 的方式,真的,如果这是解决方案,那么也许不使用 AsyncIterator 是最好的选择
有谁知道需要进行哪些更改才能使await()的代码正常工作或者我需要更改我的代码吗?
请注意,我无法返回数据集的数组,因为确实需要逐行处理。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of
forawait...of 语句创建一个迭代 async 的循环 可迭代对象以及同步可迭代对象。这个说法只能是 在可以使用await的上下文中使用,其中包括内部 异步函数体和模块中。
为了可迭代,对象必须实现 Symbol.iterator 方法,意味着该对象(或其中之一) 其原型链上的对象)必须具有一个属性 [Symbol.iterator] 键可通过常量 Symbol.iterator 获得:
Symbol.iterator 一个返回对象的零参数函数, 符合迭代器协议。
每当一个对象需要迭代时(例如在一个对象的开头) for...of 循环),它的 Symbol.iterator 方法被调用时没有 参数,返回的迭代器用于获取值 被迭代。
https://tc39.es/ecma262/#sec-asynciterable-interface
%Symbol.asyncIterator% - 返回 AsyncIterator 的函数 object - 返回的对象必须符合 AsyncIterator 接口。
为了简短起见,像这样迭代
mysql.tables()
...
for await (const it of mysql.tables()) {/*...*/}
您
.tables()
必须返回一个可迭代对象,因此为了使您的代码正常工作,您需要使用 AsyncIterable
而不是 AsyncIterator
:
interface IDriver {
tables(): AsyncIterable<Table>;
}
/*...*/
async *tables(): AsyncIterable<Table> {/*...*/}
interface Table {
name: string;
rows: number;
type: string;
}
interface IDriver {
tables(): AsyncIterable<Table>;
}
class MySql implements IDriver {
private schema: string = 'myschema';
private async query<T>(sql: string): Promise<T[]> {
return [
{ table_name: 'table1', table_type: '***', table_rows: 10 },
{ table_name: 'table2', table_type: '***', table_rows: 20 },
] as unknown as T[];
}
async *tables(): AsyncIterable<Table> {
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;
}
}
}
async function run() {
const mysql = new MySql();
for await (const table of mysql.tables()) {
console.log(table);
}
}