Comments (6)
When I talked to Josh about this previously it seemed like this was a legacy option so I wasn't planning to use it.
It's not! Many codebases use it because it provides that nice, self-documenting, no-disable-comment way to mark a promise as intentionally floating.
Josh calls it legacy because he doesn't like it and it originally became a part of the rule by accident. Way way back in the day someone did it by accident and asked for an option to catch it. And when it was added people learned it and liked it and so it became a common style.
At Canva we use it and people like it because it means no disable comments and no empty catches.
I think you're ultimately thinking about this too defensively.
A developer unfamiliar with the rule will not know what void is doing and not think twice about copy-pasting it.
You could replace void with literally any concept and have the same outcome! Disable comments, consuming functions, empty catches, no-call catches, etc. Even applies to any rule really as all rules enforce specific styles that people may copy and paste and misuse.
People will need to learn your codebase style and convention - there's likely many patterns within your codebases that are considered idiomatic style internally, but that are not used externally. It's a very common phenomenon in codebases as they evolve naturally!
Put it this way:
If someone blindly copy+pastes a voided promise to an async function and doesn't switch it to an await - they 100% would also copy paste an empty catch promise without awaiting or any other form really.
From my experience working within large react codebases (fb and canva) - you're more likely to have people forget to make a function async than you are to have people misuse the "anti-floating" tool. And both result in the same problem - that there is a floating promise - but the former is harder to track down because you need to find an unannotsted, floating promise. Whereas the void approach is very clear - just look for the void!
All that being said - I think ultimately what you want is #8404. You want to mark a promise as infallible and that is what that issue will allow you to do.
Ignoring promises in sync contexts is just a workaround for the issue of the rule reporting on infallible promises.
from typescript-eslint.
Because no-floating-promises has no good way to check if errors are caught in a function (ie using try-catch)
I'm not quite sure I understand what you mean by this. Could you give an example?
Have you considered the ignoreVoid
option?
https://typescript-eslint.io/rules/no-floating-promises/#ignorevoid
It adds a declarative way for a developer to declare "I am intentionally not awaiting this promise" and it works in both sync and async contexts.
A lot of people like it because it is "symmetrical" with the await
.
Personally I don't think this is a good option because often times you can create a promise and forget to await it, even in a sync context. If you ignore all promises in sync contexts then it's very easy to create floating promises accidentally - as in - you meant for it to be an async function but you forgot to do. So.
That is a massive bug vector in code!
OTOH if you leverage void
or disable comments or some bespoke internal thing - you can enforce the floating promise is explicitly handled as opposed to implicitly handled or forgotten.
from typescript-eslint.
Unfortunately we have some developers that will see any tool we give as a hammer so I don't want to introduce void
😅 Already I've seen one promise-inside-promise nested code with 5 nested .catch(() => {})
instead of just using a flat promise chain. That's our current massive bug vector and I've talked with Josh a couple times and haven't found a good strict way to avoid this. We're currently choosing to turn off the rule because we'd prefer seeing bugs show up as unhandled promises rather than swallowing with catch.
(I guarantee if we turn on a no-empty-catch rule people will start just copy-pasting comments. I previously opened an issue because some devs write promise.catch;
as a workaround).
Could you give an example?
async function foo() {
try {
await somePromise;
} catch (error) {
logger.log(error);
}
}
// needs .catch or void to satisfy linter even though this code should be safe
foo();
from typescript-eslint.
async function foo() { try { await somePromise; } catch (error) { logger.log(error); } } // needs .catch or void to satisfy linter even though this code should be safe foo();
What happens when logger.log
throws an unhandled exception 😬
Jokes aside - #8404 is an enhancement that would allow you to build tooling for "guaranteed infallible promises" and have the rule understand that.
previously opened an issue because some devs write promise.catch; as a workaround
no-unused-expressions
is your friend for preventing that!
Unfortunately we have some developers that will see any tool we give as a hammer so I don't want to introduce void 😅
I'm not sure I understand - how would "allow floating promises in sync contexts" be any better than "use void
to mark floating promises in sync contexts"? It seems like it's worse?
At meta the pattern we used was a function like so:
function promiseDone(p: Promise<any>): void {
p.catch(someGlobalPromiseErrorLogger);
}
useEffect(() => {
promiseDone(Promise.resolve());
});
So like void
it was clear and explicit that the intent was to not await the promise, and it also had the added benefit of ensuring the promise had error handling attached.
from typescript-eslint.
Thanks for showing the pattern from meta, that's good to know and something to investigate for us.
no-unused-expressions is your friend for preventing that!
We've turned this on since :) It solved that workaround but now unfortunately developers just use empty catch.
I'm not sure I understand - how would "allow floating promises in sync contexts" be any better than "use void to mark floating promises in sync contexts"? It seems like it's worse?
I don't want to allow using void
in a context where await
would work, such as an async function or promise chain. A developer unfamiliar with the rule will not know what void
is doing and not think twice about copy-pasting it. That might be an improvement over no flag at all so it's something we can experiment with. When I talked to Josh about this previously it seemed like this was a legacy option so I wasn't planning to use it.
from typescript-eslint.
Sounds good, I'll explore using void
in our codebase instead. I think it would be useful to have a rule/option to prevent it from being used in async functions but that's a different issue to this, so I'll close it :)
from typescript-eslint.
Related Issues (20)
- Enhancement: [naming-convention] Add an optional identifier member of each option HOT 1
- Bug: [no-inferrable-types] False positive with default parameter in closure passed to generic function HOT 1
- Repo (eslint-plugin) [consistent-type-assertions] test case missing output assertion
- Try out v8 beta on various important community repos HOT 4
- Bug: ESlint v9 server does lint in typescript monorepo HOT 5
- Repo: Weekly release flow is failing on changelogRenderer again HOT 5
- Bug: no-magic-numbers Doesn't apply ignore to type definitions HOT 3
- Enhancement: [prefer-nullish-coalescing] Ignore env vars HOT 1
- Enhancement: [no-useless-template-literals] Delete in v8
- Bug: Missing `src/util` import in `@typescript-eslint/eslint-plugin@rc-v8` with skipLibCheck: false HOT 1
- Enhancement: [prefer-literal-enum-member] Allow nested bitwise when using the `allowBitwiseExpressions` option HOT 5
- Enhancement: [no-non-null-assertion] Optionally exempt contexts where null would immediately throw at runtime HOT 12
- Bug: incorrect peer dependency "eslint@^8.56.0" HOT 2
- Bug: [explicit-function-return-type] false invalid case when using allowTypedFunctionExpressions option
- Enhancement: [await-thenable] Should check chained method calls HOT 2
- Bug: @typescript-eslint/no-unused-vars false positive when using "using" declaration statement HOT 6
- 🐛 Bug: RuleTester updates reverted in v8 branch HOT 2
- Bug: [prefer-nullish-coalescing] should consider the difference between null and undefined with strict equality HOT 2
- Bug: 8.0.0.alpha24 shared configuration with type checking fail to start HOT 1
- Bug: `no-floating-promises` should not fire on `Promise.resolve()` HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typescript-eslint.