Skip to content

Commit 4c3e704

Browse files
authored
feat(eslint-plugin): [require-await] allow yielding Promise in async generators (typescript-eslint#8003)
* feat(eslint-plugin): [require-await] allow yielding Promise in async generators * chore: refactor `visitYieldExpression` a bit
1 parent 314f034 commit 4c3e704

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

Diff for: packages/eslint-plugin/src/rules/require-await.ts

+15-6
Original file line numberDiff line numberDiff line change
@@ -112,18 +112,27 @@ export default createRule({
112112
}
113113

114114
/**
115-
* mark `scopeInfo.isAsyncYield` to `true` if its a generator
116-
* function and the delegate is `true`
115+
* Mark `scopeInfo.isAsyncYield` to `true` if it
116+
* 1) delegates async generator function
117+
* or
118+
* 2) yields thenable type
117119
*/
118-
function markAsHasDelegateGen(node: TSESTree.YieldExpression): void {
120+
function visitYieldExpression(node: TSESTree.YieldExpression): void {
119121
if (!scopeInfo?.isGen || !node.argument) {
120122
return;
121123
}
122124

123125
if (node.argument.type === AST_NODE_TYPES.Literal) {
124-
// making this `false` as for literals we don't need to check the definition
126+
// ignoring this as for literals we don't need to check the definition
125127
// eg : async function* run() { yield* 1 }
126-
scopeInfo.isAsyncYield ||= false;
128+
return;
129+
}
130+
131+
if (!node.delegate) {
132+
if (isThenableType(services.esTreeNodeToTSNodeMap.get(node.argument))) {
133+
scopeInfo.isAsyncYield = true;
134+
}
135+
return;
127136
}
128137

129138
const type = services.getTypeAtLocation(node.argument);
@@ -152,7 +161,7 @@ export default createRule({
152161
AwaitExpression: markAsHasAwait,
153162
'VariableDeclaration[kind = "await using"]': markAsHasAwait,
154163
'ForOfStatement[await = true]': markAsHasAwait,
155-
'YieldExpression[delegate = true]': markAsHasDelegateGen,
164+
YieldExpression: visitYieldExpression,
156165

157166
// check body-less async arrow function.
158167
// ignore `async () => await foo` because it's obviously correct

Diff for: packages/eslint-plugin/tests/rules/require-await.test.ts

+24
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,30 @@ async function* foo(): Promise<string> {
237237
await using foo = new Bar();
238238
};
239239
`,
240+
`
241+
async function* test1() {
242+
yield Promise.resolve(1);
243+
}
244+
`,
245+
`
246+
function asyncFunction() {
247+
return Promise.resolve(1);
248+
}
249+
async function* test1() {
250+
yield asyncFunction();
251+
}
252+
`,
253+
`
254+
declare const asyncFunction: () => Promise<void>;
255+
async function* test1() {
256+
yield asyncFunction();
257+
}
258+
`,
259+
`
260+
async function* test1() {
261+
yield new Promise(() => {});
262+
}
263+
`,
240264
],
241265

242266
invalid: [

0 commit comments

Comments
 (0)