-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Bug: [no-floating-promises] Incorrect handling of finally calls #5692
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
Comments
finally
callsfinally
calls
finally
calls
Hmm, we'd explicitly made this the behavior in #1603 -> #1620. But now I'm not so sure this was the right move. console.log("a");
Promise.resolve().finally(() => {
throw new Error("Finally!");
});
console.log("b");
cc @a-tarasyuk @bradzacher for historical context. Perhaps we should make the ignoring of |
Floating promises can't be entirely avoided, since p.finally(handle)
// …same as…
p.then(
async (result) => {
await handle()
return result
},
async (error) => {
await handle()
throw error
}
) …and so they should be treated the same as |
Another case that should probably be fixed: // Nothing reported by linter.
demoFunction(true).then(() => {
console.log('Entered then');
}, (error) => {
console.log('Entered catch');
}); In this case (perhaps unintuitively), errors thrown in the success handler aren't caught by the rejection handler. The above code is equivalent to this monstrosity… const catchReturn = Symbol.for('promise.catchReturn');
demoFunction(true).catch((error) => {
console.log('Entered catch');
// Throw to skip the success handler. Use a symbol to identify our throw.
throw { [catchReturn]: undefined };
}).then(() => {
console.log('Entered then');
}).catch((error) => {
if (error && error[catchReturn]) {
return error[catchReturn];
}
throw error;
}); …which should be (but isn't) reported by the We can get an equivalent implementation of my last two examples to be reported by the const caught = Symbol.for('promise.caught');
demoFunction(true).catch(() => {
console.log('Entered catch');
// Return a symbol to signify an error was caught.
return caught;
}).then((result) => {
if (result !== caught) {
console.log('Entered then');
}
}); …so I think it stands to reason that the first 2 examples should also be reported. |
In #1620 it was written that So what should the handling be? I think that I.e. // BAD
prom;
prom.then(f);
prom.finally(f);
prom.then(f).finally(f);
prom.finally(f).then(f).finally(f);
// GOOD
prom.then(f, f).finally(f);
prom.catch(f).finally(f);
prom.then(f).catch(f).finally(f);
prom.then(f).finally(f).catch(f).finally(f);
prom.catch(f).finally(f).finally(f).finally(f).finally(f).finally(f).finally(f).finally(f); The last caveat mentioned above is something to consider - should a prom.catch(f).finally(f).catch(f); Which is really cumbersome. |
I am working on a PR (#6881) which forced me to think about this a bit... For the purposes of that PR I regarded I'd be happy to look into putting up a PR for this issue as well. To build off of @bradzacher's suggestions: I also noticed that from the point of view of avoiding literal unhandled rejections, finally can only make an unhandled promise worse. However, the more I think about it, I can also understand the argument that adding a My preference for this rule would be to make a
JS/TS is not an exception-safe language, so I think it would be overbearing to consider the possibility of the finally handler throwing. Actually, I think that a
So let's just take the fact that One more thought, just to take this argument ad absurdum, by turning to synchronous equivalent again:
finally handlers are never truly safe - that's just a limitation of JS. The linter can't compensate for this. |
My attempt to reduce the desired behavior (IMO) to its clearest and simplest form is as follows:
Does that clear things up? |
Strongly disagree with this because you're forcing users to write Capturing developer intent is important here - The fix for this issue is to just ignore |
Before You File a Bug Report Please Confirm You Have Done The Following...
Playground Link
https://typescript-eslint.io/play/#ts=4.8.3&sourceType=module&code=MYewdgzgLgBAJgUwLYgGIFczCgS3ALhgAocwAHdKQgIxBABsEBDMAShgF4A+GABQCcQSHBAQAeaP1IBzHh2KkKVGLQbM2nHgG8AUDBg4AZgvKV2u-fv4Io6fmD6DhogHTWIDAG4IiAcgAWCPT0IDAA7iD89HC+rADcejAAvjBBojAWlta29o5CIghuCABWCNh+ipThTBAwhkz0orEJ+kk6bTqIKBhYuOBEUPzoCKwuUIFgRETs3BmJoJBqLiHSfgCiYFAI1nAw4whgze2jhqQN9ACeUzPa8+AejMsgq74bWzt1Z8EXR0nxQA&eslintrc=N4KABGBEBOCuA2BTAzpAXGUEKQAIBcBPABxQGNoBLY-AWhXkoDt8B6Jge1oDN4OBDfMwDmtYtA4BbSshTooiaBOiRwYAL4h1QA&tsconfig=N4KABGBEDGD2C2AHAlgGwKYCcDyiAuysAdgM6QBcYoEEkJemy0eAcgK6qoDCAFutAGsylBm3TgwAXxCSgA
Repro Code
ESLint Config
tsconfig
No response
Expected Result
There is no
.catch
call, and the rule should report it.Actual Result
Nothing reported
Additional Info
No response
Versions
@typescript-eslint/eslint-plugin
5.31.0
@typescript-eslint/parser
5.31.0
TypeScript
4.7.4
ESLint
8.20.0
node
18.7.0
The text was updated successfully, but these errors were encountered: