Skip to content
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

Type definitions are wrong, don't allow Promise to be returned (caught by @typescript-eslint) #230

Open
rdsedmundo opened this issue Mar 20, 2021 · 9 comments · May be fixed by #231
Open

Comments

@rdsedmundo
Copy link

rdsedmundo commented Mar 20, 2021

Env:

TypeScript: 4.1.3
Express: 4.17.1
Node: 14.16.0
@typescript-eslint/eslint-plugin: 4.17.0
@typescript-eslint/parser: 4.17.0

Repro:

import express from 'express';
import createRouter from 'express-promise-router';

export const router = createRouter();

router.get(
  '/',
  async (req: express.Request, res: express.Response): Promise<string> => {
    res.sendStatus(200);
  },
);

export const server = express().use(router);

Produces:

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

This is because the type definitions from express-promise-router are just using the express.Router interface which doesn't support Promises (the very reason why this package exists).

@mormahr
Copy link
Member

mormahr commented Mar 21, 2021

Hi,

we don’t send out values returned by the promises. We want to avoid values being implicitly returned by a promise chain to end up at the client. It would also be hard to support status codes and the like. We run the promises and forward errors, but you have to send the values yourself. See the section „Why aren't promise values sent to the client“ in the readme.

If you want to send a string, like I assume you wanted in your example, you call res.send().

import express from 'express';
import createRouter from 'express-promise-router';

export const router = createRouter();

router.get(
  '/',
  async (req: express.Request, res: express.Response): Promise<void> => {
    res.status(200).send('Hello World');
  },
);

export const server = express().use(router);

I hope this cleared up any confusion.
Don’t hesitate to ask if you have any other issues.

As an aside:
I didn‘t originally contribute the type definitions, so I haven’t checked if they support the two return values we actually do allow ('next' and 'route'), but I’ll check that next week.

@rdsedmundo
Copy link
Author

Thanks for the reply, @mormahr.

I'm aware of the Promise/response behavior, but this is not the issue. As soon as you mark a function with the async keyword it automatically returns a Promise.

@mormahr
Copy link
Member

mormahr commented Mar 21, 2021

Yes and that's correct, but it has to return Promise<void> like in my example.

@mormahr
Copy link
Member

mormahr commented Mar 21, 2021

I think i understand what you mean now. It's not a TypeScript error, it's that ts eslint thinks the promise is unused. I'll have a look later.

@rdsedmundo
Copy link
Author

Yep, exactly. It states that because the return signature from the Router interface doesn't say that a Promise is returned.

@mormahr mormahr linked a pull request Mar 21, 2021 that will close this issue
@mormahr
Copy link
Member

mormahr commented Mar 21, 2021

I added a failing test case in #231.
I feel like the only way to fix this is to duplicate part of the express typings to overwrite all the handler types.

@mobeigi
Copy link

mobeigi commented Sep 25, 2021

Would be nice to merge this so consumers don't have to disable the lint rule for every async router. Its a useful typescript eslint rule so you don't want to disable it globally.

@mormahr
Copy link
Member

mormahr commented Sep 25, 2021

There is nothing to merge. I wrote a failing test case but actually solving this isn't trivial as (as far as I can tell) we need to duplicate lots of definitions from @types/express. I haven't had the time to look into this again since then.

@mormahr
Copy link
Member

mormahr commented Nov 30, 2021

From what I've tried, the problem is essentially that in the type definition of express-serve-static-core the return type of a handler is defined as void where we would need it to be void | Promise<void>. But since this type is buried so far down the chain of types, it's hard to replace it.

I might contact the maintainers of the @types/express and @types/express-serve-static-core and ask for advice/help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants