-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat(eslint-plugin): [await-thenable] check for-await loop iteree #10008
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(eslint-plugin): [await-thenable] check for-await loop iteree #10008
Conversation
Thanks for the PR, @kirkwaiblinger! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏 Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently on https://opencollective.com/typescript-eslint. |
## Async Iteration (`for await...of` Loops) | ||
|
||
This rule also inspects [`for await...of` statements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of), which are designed for iterating over async-iterable objects. | ||
If the value being iterated over is not async-iterable, an ordinary `for...of` statement is preferable, even if the value is an iterable of Thenables. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is debatable. Banning iterables of thenables should be an option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh, kind of... in any case, I was going off of #8858 (comment). It's easy enough to add an option to allow iterables of thenables, though I'm -0.5 on doing so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In lieu of an option, can we add more motivation to the docs (as what I said in that comment)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! Made some changes around this 👍
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #10008 +/- ##
==========================================
+ Coverage 86.00% 86.03% +0.02%
==========================================
Files 425 428 +3
Lines 14810 14930 +120
Branches 4308 4329 +21
==========================================
+ Hits 12738 12845 +107
- Misses 1723 1741 +18
+ Partials 349 344 -5
Flags with carried forward coverage won't be shown. Click here to find out more.
|
❌ Deploy Preview for typescript-eslint failed.
|
✅ Deploy Preview for typescript-eslint ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
// This suggestion causes broken code for sync iterables of promises, since | ||
// the loop variable will not be awaited. | ||
// | ||
// Ideally, if the iterable yields promises, we would offer a suggestion to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bleh - I guess this isn't always a good idea, particularly with possibly infinite iterables. But, then again, why would you have an infinite sync iterable of promises? Thinking out loud.
context.report({ | ||
loc: getForStatementHeadLoc(context.sourceCode, node), | ||
messageId: 'forAwaitOfNonThenable', | ||
suggest: [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we only offer this suggestion if the iterator result is not thenable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so because we'd need getIterationTypesOfIterable()
or getIteratedTypeOrElementType
or similar from TS none of which is exposed on the checker
.
If we check arrays and tuples specifically, i.e. known iterables, this is silly since
for (const promisedValue of await Promise.all(promises)) {
}
is a much better suggestion in those cases (since await
ing in the loop is generally problematic for exception handling given a non-lazy array of promises)
Whereas with lazy sync-iterables of promises, which I don't know if we can detect, it may be better to do
for (const promise of yieldPromises()) {
const promisedValue = await promise;
}
I guess the only thing that's unambiguous here is that if you have an array or tuple of non-thenables, this suggestion is good. Maybe that's the only situation where we give a suggestion?
Co-authored-by: Joshua Chen <[email protected]>
Co-authored-by: Joshua Chen <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wholly satisfied with this, except for the one line of missing test coverage. Then we're good to go IMO! 🚀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚢
b121bd9
into
typescript-eslint:main
wrong rule in title lol |
smh 😞. Changing the title and release notes, thanks for pointing this out! |
PR Checklist
for-await
loop is used on an async iterable #8858Overview
Just ask the type checker if a
Symbol.asyncIterator
is present, ezpz. Add tests and docs (less ezpz).