8000 [no-misused-promises] async react callback properties when void expected · Issue #4619 · typescript-eslint/typescript-eslint · GitHub
[go: up one dir, main page]

Skip to content

[no-misused-promises] async react callback properties wh 8000 en void expected #4619

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

Closed
3 tasks done
jlowcs opened this issue Mar 1, 2022 · 12 comments · Fixed by #4623
Closed
3 tasks done

[no-misused-promises] async react callback properties when void expected #4619

jlowcs opened this issue Mar 1, 2022 · 12 comments · Fixed by #4623
Assignees
Labels
accepting prs Go ahead, send a pull request that resolves this issue enhancement: plugin rule option New rule option for an existing eslint-plugin rule package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin

Comments

@jlowcs
Copy link
jlowcs commented Mar 1, 2022
  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.
  • I have read the FAQ and my problem is not listed.

Repro

{
  "rules": {
    "no-misused-promises": ["error"]
  }
}
			<button
				type="button"
				onClick={async () => {
					await doSomethingAsync();
				}}
			>
				action
			</button>

or

			<button type="button" onClick={doSomethingAsync}>
				action
			</button>

Expected Result

No linting error.

Actual Result

A linting error is being reported:

src/app/App.tsx
  129:13  error  Promise-returning function provided to attribute where a void return was expected  @typescript-eslint/no-misused-promises

One way to avoid this error would be to wrap the callback's content in an async IIFE:

			<button
				type="button"
				onClick={() => {
					(async () => {
						await doSomethingAsync();
					})();
				}}
			>
				action
			</button>

But that's not really practical when the callback is an existing function (like the 2nd example above).

Additional Info

I guess this new behavior is kind of expected, but it's probably gonna breaks linting on a lot of React projects (including ours, which has now over 100 erros following this update). I'll welcome any suggestion as to how to address it without simply disabling the rule (and risk missing some potential bugs that were detected before).

Versions

package version
@typescript-eslint/eslint-plugin 5.13.0
@typescript-eslint/parser 5.13.0
TypeScript 4.5.5
ESLint 8.10.0
node 16.13.2
@jlowcs jlowcs added package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Mar 1, 2022
@bradzacher
Copy link
Member

As you mentioned - this is a correct report as there is a potential bug due to the dangling promise left behind.

It's hard because it's not really possible for us to detect this case of "acceptable" usage. So it's really, really hard to allowlist some subset of the cases.

Maybe this new logic should be put behind an option instead to allow people to opt-out of it?


Side note that you can also use this style to mark the promise as purposely dangling (which is more easily greppable, and is supported in our no-floating-promises lint rule)

<div
  onClick={
    () => {
      void doSomethingAsync();
    }
  }
  onClick={
    () => {
      void (async () => {
        const x = await doSomethingAsync();
        doSomethingElse(X);
      })();
    }
  }
/>

@bradzacher bradzacher added awaiting response Issues waiting for a reply from the OP or another party and removed triage Waiting for team members to take a look labels Mar 1, 2022
@jlowcs
Copy link
Author
jlowcs commented Mar 1, 2022

Thank you for responding @bradzacher.

I'm thinking about writing a utility function for this purpose:

function wrapAsyncFunction<ARGS extends unknown[]>(fn: (...args: ARGS) => Promise<unknown>): (...args: ARGS) => void {
	return (...args) => {
		void fn(...args);
	};
}

So we can use it this way:

<button type="button" onClick={wrapAsyncFunction(doSomethingAsync)}>
	action
</button> 

I'm not a big fan of wrapAsyncFunction as a name though, as it doesn't really tell anything about its purpose. Maybe you'd have a name suggestion @bradzacher? :)

@bradzacher
Copy link
Member

I'm a fan of being verbose and descriptive, so I'd do something like intentionalyFloatingPromiseReturn or something.

@JoshuaKGoldberg
Copy link
Member

Maybe this new logic should be put behind an option instead to allow people to opt-out of it?

Agreed, this is a pretty common pattern for state libraries such as React. Agreed the rule is technically correct but in the spirit of not being a pain for users I'll add an option to disable this specific check.

@JoshuaKGoldberg JoshuaKGoldberg added working as intended Issues that are closed as they are working as intended and removed awaiting response Issues waiting for a reply from the OP or another party labels Mar 1, 2022
@JoshuaKGoldberg
Copy link
Member

Oh, actually, a checksVoidReturn already exists! https://typescript-eslint.io/rules/no-misused-promises#checksvoidreturn-true. When I enable checksVoidReturn locally it stops the OP's issues.

Thanks for the report @jlowcs! I'm going to go ahead and close this issue as working as intended, but if you do have a repro please do post back.

@jlowcs
Copy link
Author
jlowcs commented Mar 1, 2022

@JoshuaKGoldberg indeed, checksVoidReturn: false works, but it will also remove checks that were made before this change, which we might have been relying upon.

@JoshuaKGoldberg
Copy link
Member

Do you have an example of those? If there's a good delineation between pre-change issues and post-change, we could always take >=1 rule option.

(or maybe just add rule options for everything in the change?)

@JoshuaKGoldberg JoshuaKGoldberg added awaiting response Issues waiting for a reply from the OP or another party enhancement: plugin rule option New rule option for an existing eslint-plugin rule and removed working as intended Issues that are closed as they are working as intended labels Mar 1, 2022
@lgenzelis
Copy link
Contributor

I'm having the same issue as OP. React code like<button type="button" onClick={doSomethingAsync}>action</button>, which used to be accepted, started to be reported as an error after #4541 . I understand that the report is actually correct, but it leaves me with adding '@typescript-eslint/no-misused-promises': ['error', { checksVoidReturn: false }] as my only choice if I want to keep writing code like that.

Also, since the error text is something specific to this new kind of reported error (promise-returning function provided to attribute where a void return was expected), I'm wondering if it would be much trouble to disable this specific case. Idk, something like '@typescript-eslint/no-misused-promises': ['error', { checksVoidReturningArgument: false }].

@jlowcs
Copy link
Author
jlowcs commented Mar 2, 2022

@JoshuaKGoldberg https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-misused-promises.md#checksvoidreturn-true provides some examples that we'd still like to be able to benefit from :)

@JoshuaKGoldberg
Copy link
Member

Got it, that makes sense - thank you two! Marking as accepting PRs to add in an opt-out option for each of the new error locations added in https://github.com/typescript-eslint/typescript-eslint/pull/4541/files#diff-dd469c96cb4a7fd7e266d9957762126ca0e669b65eb00173edcf40d1dcdced6fR33.

This seems to be a hot issue so I'll go ahead and send that PR later today. I feel responsible for this as I should have caught the significance of the breaking changes in review 🙂.

@JoshuaKGoldberg JoshuaKGoldberg self-assigned this Mar 2, 2022
@JoshuaKGoldberg JoshuaKGoldberg added accepting prs Go ahead, send a pull request that resolves this issue and removed awaiting response Issues waiting for a reply from the OP or another party labels Mar 2, 2022
@jlowcs
Copy link
Author
jlowcs commented Mar 2, 2022

Thank you @JoshuaKGoldberg, I really appreciate it :)

@borisovg
Copy link
borisovg commented Mar 4, 2022

For the record, this also breaks async Mocha tests, e.g.

// error  Promise returned in function argument where a void return was expected  @typescript-eslint/no-misused-promises
it('test that uses await', async () => {
  ...
});

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 24, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepting prs Go ahead, send a pull request that resolves this issue enhancement: plugin rule option New rule option for an existing eslint-plugin rule package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin
Projects
None yet
5 participants
0