Promise returned in function argument where a void return was expected
Asked Answered
W

5

52

I'm working on an Electron application and I want to use async await in an anonymous function in my Main like this:

process.on("uncaughtException", async (error: Error) => {
  await this.errorHandler(error);
});

But this yields the Typescript error

Promise returned in function argument where a void return was expected.

I'm using Typescript 3.9.7 and Electron 9.2.0.

Why doesn't it allow me to use async/await?

Wojcik answered 19/8, 2020 at 13:32 Comment(2)
An async function always returns a promise, so it can't be passed where a void function is expected. Why not just call the error handler, what are you trying to wait for?Abrade
In general, don't pass async functions into things that won't use the promise they return. TypeScript is helping you avoid doing that with this error.Heigl
C
74

You can use an asynchronous IIFE inside the callback, like this:

process.on("uncaughtException", (error: Error) => {
  (async () => {
    await this.errorHandler(error);

    // ...
  })();
});

This ensures that the implicit return of the callback remains undefined, rather than being a promise.

Cotton answered 19/8, 2020 at 13:35 Comment(5)
Just be sure to handle promise rejection correctly.Heigl
Is there a good reason to do that, beyond removing the eslint error?Alimentary
@Henrique Bruno Functionally, no. Semantically, yes — it signals clearly that this is a "fire and forget" operation and that the callback itself doesn't do anything special with the asynchronous code (doesn't await it or do anything with the result).Cotton
@LionelRowe Simple and mind expanding answer. Thanks! I will, however, keep this ESLint rule disabled as I think that it being enabled, adds an unnecessary complexity and verbosity level for my uses.Alimentary
I have a similar case here: onClick={ () => UtilClass.getName(a, b).then( (name) => { UtilClass.delete(name, x, y); }) } It is giving me @typescript-eslint/no-misused-promises error. How should I fix it in my case?Choriamb
Q
21

Fixed it, I found the answer below from here

 <div
  onClick={
    () => {
      void doSomethingAsync();
    }
  }
  onClick={
    () => {
      void (async () => {
        const x = await doSomethingAsync();
        doSomethingElse(X);
      })();
    }
  }
/>
Quyenr answered 2/10, 2022 at 4:25 Comment(3)
it works but it looks awfull, I'd rather disable the rule lolBoldt
I have a similar case here: onClick={ () => UtilClass.getName(a, b).then( (name) => { UtilClass.delete(name, x, y); }) } It is giving me @typescript-eslint/no-misused-promises error. How should I fix it in my case?Choriamb
This actually affects the outcome of the callback in button elements. I've experienced a preventDefault() bug, it submits the form regardless. removing the void solved it.Recant
F
15

You can turn off this check (not the entire rule) with the help of checksVoidReturn option:

.eslinter.js

rules: {
    {
      "@typescript-eslint/no-misused-promises": [
        "error",
        {
          "checksVoidReturn": false
        }
      ]
    }
}

But I strongly recommend not to do this and rewrite your code using .then and .catch to avoid hitting this linter error.

You may also disable this rule inline with // eslint-disable-next-line @typescript-eslint/no-misused-promises comment above this particular occurrence along with a few lines of comment describing why you think this is okay to ignore the error.

Friar answered 18/11, 2021 at 3:4 Comment(0)
R
3

You can simply remove async keyword from the lambda function and add catch clause to prevent an unhandled promise rejection.

process.on("uncaughtException", (error: Error) => {
  this.errorHandler(error).catch((e) => console.error(e));
});

The reason you are getting this error is, process.on expects its lambda function to return void, not Promise<void>, and your lambda function is never going to be awaited.

This is important, because without await keyword an unhandled promise rejection may be triggered which crashes the entire process immediately.

Look at the following example:

function middleware(f) {
    f();
}

middleware(async () => {
    throw "Error!";
});

Now, when I run this file, an error message will pop up:

node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Error!".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

This is because the promise was never awaited, and therefore Node.js didn't know what to do with the error thrown by the promise.

Simply adding catch like this clause will fix the problem.

function middleware(f) {
    f().catch((e) => console.error(e));
}

middleware(async () => {
    throw "Error!";
});

Note: adding catch clause is not mandatory in a browser environment because unhandled promise rejection will not result in immediate crash in the browser environment.

Rigadoon answered 19/11, 2023 at 4:38 Comment(0)
L
-3

This is the official TS ESLint solution and I recommend you update your .eslintrc config file with:

"@typescript-eslint/no-misused-promises": [
    2,
    {
        "checksVoidReturn": {
            "attributes": false
        }
    },
]

Check this Pull Request for more info https://github.com/typescript-eslint/typescript-eslint/pull/4623

Lauranlaurance answered 3/5, 2023 at 11:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.