TypeScript/Eslint 在 Express Router 异步路由上抛出“Promise returned”错误

Hi*_*bo 14 node.js typescript eslint typeorm express-router

我有以下端点设置来在测试运行后重置数据库:

import { getConnection } from 'typeorm';
import express from 'express';
const router = express.Router();

const resetDatabase = async (): Promise<void> => {
  const connection = getConnection();
  await connection.dropDatabase();
  await connection.synchronize();
};

// typescript-eslint throws an error in the following route:
router.post('/reset', async (_request, response) => {
  await resetTestDatabase();
  response.status(204).end();
});

export default router;
Run Code Online (Sandbox Code Playgroud)

此后的整个路线都async带有下划线,并带有 typescript-eslint 错误Promise returned in function argument where a void return was expected.

该应用程序工作完美,但我不确定我是否应该执行更安全的实现,或者只是忽略/禁用此应用程序的 Eslint。知道该代码有什么问题吗?

小智 16

我找到了一个不涉及使用的解决方案then(),让您使用异步的抽象而不会被 eslint 诅咒,有两个解决方案(但我更推荐第二个)

第一个解决方案:使用“内部异步”

这是在 void 中使用异步的基本方法,如下所示:

router.post('/reset', (_request, response) => {
    (async () => {
        await resetTestDatabase();
        response.status(204).end();
    })()
});
Run Code Online (Sandbox Code Playgroud)

第二种解决方案(推荐):“类型重叠”

第二个选项是你将它用作异步,就像Always一样,但是用“as”关键字说“嘿TypeScript,这里没有什么问题呵呵”

import { RequestHandler } from 'express'

router.post('/reset', (async (_request, response) => {
    await resetTestDatabase();
    response.status(204).end();
}) as RequestHandler);
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是一个很好的问题!为什么要使用 eslint?对我来说,这是围绕代码强制执行某些规则,以确保代码更好。如果应用一条规则会使代码变得更糟,那么它就不是一个好规则。 (2认同)

Mag*_*gie 9

在参观了一些房子之后,这里有一个更新:

Express 5 现在可以正确处理这个问题。Express 维护者在此确认:

然而,(在撰写本文时)Express 5 的打字尚未更新/可用,因此尽管已解决,但错误仍然显示。请关注这里的DefinelyTyped 存储库以获取有关更新的对话。

同时,正如KuryKat已经建议的那样,在 Express 5 中使用 进行处理RequestHandler应该是安全的。

import { RequestHandler } from 'express'

router.post('/reset', (async (_request, response) => {
    await resetTestDatabase();
    response.status(204).end();
}) as RequestHandler);
Run Code Online (Sandbox Code Playgroud)

然而,在 Express 4 中,最好使用显式的方法来处理错误.catch(...)

app.get("/manifest.webmanifest", (_req, res) => {
  getManifest(pwaOptions)
    .then(result => res.send(result))
    .catch(error => res.status(500).send('Unexpected error'))
});
Run Code Online (Sandbox Code Playgroud)

或者使用异步处理程序:

快速异步处理程序

快速异步路由器

请参阅此处有关 Express 4 的讨论以供参考。


cdi*_*las 4

看来您正在使用“不滥用承诺”规则,该规则规定您不能返回预期的Promise<void>地方。void

这意味着您无法Promise<void>从 Express 处理程序返回,因为来自库的返回类型RequestHandler指定返回类型应为void. 我建议您Promise<Response>通过添加一个简单的return关键字将其更改为 return:

import { getConnection } from 'typeorm';
import express from 'express';
const router = express.Router();

const resetDatabase = async (): Promise<void> => {
  const connection = getConnection();
  await connection.dropDatabase();
  await connection.synchronize();
};

// typescript-eslint throws an error in the following route:
router.post('/reset', async (_request, response) => {
  await resetTestDatabase();
  return response.status(204).send();  // <----- return added here
});

export default router;
Run Code Online (Sandbox Code Playgroud)

另一种选择是避免使用async/await

router.post('/reset', (_request, response) => {
  resetDatabase().then(() => response.status(204).send());
});
Run Code Online (Sandbox Code Playgroud)

  • 当您将“async”添加到函数时,它会自动将返回类型设为“Promise”。如果您像在“async”函数中那样不返回任何内容,则返回类型为“Promise&lt;void&gt;”,而不仅仅是“void”。老实说,我不确定 linting 规则是否值得,所以我很想禁用它。 (8认同)
  • 陛下不喜欢。我们只能花这么多时间来安抚 Typescripot :P 我就离开 then(),再次感谢伙计! (2认同)
  • 有没有办法不用 then() 来解决这个问题? (2认同)