14

What should I do with function of registration to fix @typescript-eslint/no-misused-promises. The one way I found how to fix this problem is write by eslint.

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

But I'd like to solve this problem as so as eslint requires. Any ideas?

import PromiseRouter from "express-promise-router";
import { login, registration } from './authController';

const router = PromiseRouter();


> ESLint: Promise returned in function argument where a void return was
> expected.(@typescript-eslint/no-misused-promises)

router.post('/registration', registration);

Here is full function of registration

export async function registration(req: TreqBodyReg, res: Response): Promise<void> {
  try {
    const { email, password } = req.body;
    const candidate = await ModelUser.findOne({ email }) as TuserFromDB;
    if (candidate) {
      res.status(400).json({ message: `There is user with email ${email}` });
      return;
    }
    const hashPassword = bcrypt.hashSync(password, 7);
    const user = new ModelUser({ email, password: hashPassword });
    await user.save();
    res.status(200).json({ message: `The user by email ${email} was successfully registered` });
  } catch (err: unknown) {
    res.status(400).json({ message: err });
  }
};
2
  • Did you manage to solve this? Commented Feb 9, 2021 at 14:59
  • not for a while( Commented Feb 9, 2021 at 17:34

5 Answers 5

4

I've encountered the same problem using the default Router and solved it by doing this:

router.get("/", function(request: Request, response: Response): void {
  void (async function(): Promise<void> {
    // do your asychronous work here
    response.json(/* put your payload here */);
  })();
});

I admit that I'm not fond of the extra boilerplate, but it's the best answer I've found so far.

The (async function(): Promise<void> {...})(); part is just an asyncronous self-invoking function (note the extra () at the end). The void in front of it drops the return type so that ESLint knows you really intend to ignore the returned promise. Without it, you get a "no-floating-promises" error. Of course, that means you are taking responsibility for using try-catch internally to deal with errors...

So, the end result with this approach is that the extra boilerplate allows you to to use async/await in the default Express Router.

Sign up to request clarification or add additional context in comments.

Comments

1

It's roundabout, but I solved the problem this way.

async function registerUser(req: TreqBodyReg, res: Response): Promise<void> {
  const { email, password } = req.body;
  const candidate = await ModelUser.findOne({ email }) as TuserFromDB;
  if (candidate) {
    res.status(400).json({ message: `There is user with email ${email}` });
    return;
  }
  const hashPassword = bcrypt.hashSync(password, 7);
  const user = new ModelUser({ email, password: hashPassword });
  await user.save();
  res.status(200).json({ message: `The user by email ${email} was successfully registered` });
}

export function registration(req: TreqBodyReg, res: Response): void {
  registerUser(req, res).catch((err: unknown) => {
    res.status(400).json({ message: err });
  });
}

Comments

1

The way I've solved the error is by creating a custom asyncHandler function.

The @typescript-eslint/no-misused-promises rule is there because if an async function throws an error, it won't be caught and passed to the next middleware unless explicitly handled. To explicitly handle potential errors, asyncHandler catches the errors and passes them to the next function. Passing them to the next function in express is the standard way to handle errors in Express.

function asyncHandler(
  fn: (
    req: express.Request,
    res: express.Response,
    next: express.NextFunction
  ) => Promise<void>
) {
  return function handler(
    req: express.Request,
    res: express.Response,
    next: express.NextFunction
  ) {
    fn(req, res, next).catch((error: unknown) => {
      next(error);
    });
  };
}

app.get('/route', asyncHandler(async (req, res, next) => {
  const data = await someAsyncOperation();
  res.send(data);
}));

Otherwise, without asyncHandler in this example, the async function might throw an error that isn't caught and passed to next.

This also works with router.get, any Express route handler, including those defined on a router instance.

router.get('/route', asyncHandler(async (req, res, next) => {
  const data = await someAsyncOperation();
  res.send(data);
}));

You could also solve this eslint problem with .thens and .catchs, but that is less readable/modern code (in my opinion).

Comments

0

It will be caused by using try catch with await inside of your callback for your middleware. You can either use a self invoked function like in the answer from @Andrew or you can handle it aswell like this:

// Sample route to trigger HttpClientError
app.get('/httpclient-error', (): void => {
    axios.get(`${BASE_URL}/notFound`)
        .then(() => {
            // handle successful response
        })
        .catch((e: AxiosError) => {
             // do something
        })
})

However, if your are working with express-async-errors and your callback should be able throw a new error, then this will not work because your callback must be an async function. So for this case you must use the rule:

 // Sample route to trigger HttpClientError
    app.get('/httpclient-error', async() => {
        try {
            await axios.get(`${BASE_URL}/notFound`)
        } catch (e) {
            throw new HttpClientError(errorMessage, e as AxiosError)
        }
    })
'@typescript-eslint/no-misused-promises': [
    'error',
    {
        'checksVoidReturn': false
    }
]

Comments

0

Shorter version of dropping the promise:

router.post('/registration', (req, res, next) => void registration(req, res, next));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.