Closed dko-slapdash closed 3 years ago
In a way yes, this library like those you’ve mentioned aims to solve the same problem - not having to manually catch rejected promises in middlewares and send err to global handler. However there are 2 main differences:
Router#param
middleware and2 more cents/FYIs here:
no-misused-promises
rule (it just doesn't allow passing async handlers to a callback which is expected to return void
). Express authors made TS typing stricter, it doesn't accept async handlers anymore.no-misused-promises
rule which doesn't always verify that the async handlers are treated properly, I reported it here: https://github.com/typescript-eslint/typescript-eslint/issues/4015 - I found a work-around though, mentioned in the issue above.Our story: after upgrading Express and TS, we had to stop using express-async-errors and switched to express-async-handler; to do so, we had to apply the work-around for no-misused-promises eslint rule mentioned above.
@kronicker JFYI, if you couple express-async-errors with TS typing which allows async handlers to be passed to express router matcher/handler (recent Express enforces all the handlers to return void
and not a Promise), then it would make the library even better. (I understand that it currently has nothing to do with TS, but anyways.) Below is a code snippet which we used to work-around a bug in no-misused-promises
eslint rule https://github.com/typescript-eslint/typescript-eslint/issues/4015 - if adjusted accordingly, the similar approach may allow people to use async handlers, express-async-errors library, recent Express and no-misused-promises
eslint rule together.
import { ParsedQs } from "qs";
// See https://github.com/typescript-eslint/typescript-eslint/issues/4015 to
// understand why. Once it's resolved (if it is), we can remove this file and
// this folder.
declare module "@types/express-serve-static-core" {
export interface IRouterMatcher<
T,
Method extends
| "all"
| "get"
| "post"
| "put"
| "delete"
| "patch"
| "options"
| "head" = any
> {
<
Route extends string,
P = RouteParameters<Route>,
ResBody = any,
ReqBody = any,
ReqQuery = ParsedQs,
Locals extends Record<string, any> = Record<string, any>
>(
// tslint:disable-next-line no-unnecessary-generics (it's used as the default type parameter for P)
path: Route,
// tslint:disable-next-line no-unnecessary-generics (This generic is meant to be passed explicitly.)
handler1: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler2?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler3?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler4?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler5?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>
): T;
<
Path extends string,
P = RouteParameters<Path>,
ResBody = any,
ReqBody = any,
ReqQuery = ParsedQs,
Locals extends Record<string, any> = Record<string, any>
>(
// tslint:disable-next-line no-unnecessary-generics (it's used as the default type parameter for P)
path: Path,
// tslint:disable-next-line no-unnecessary-generics (This generic is meant to be passed explicitly.)
handler1: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler2?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler3?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler4?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler5?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>
): T;
<
P = ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = ParsedQs,
Locals extends Record<string, any> = Record<string, any>
>(
path: PathParams,
// tslint:disable-next-line no-unnecessary-generics (This generic is meant to be passed explicitly.)
handler1: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler2?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler3?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler4?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler5?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>
): T;
<
P = ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = ParsedQs,
Locals extends Record<string, any> = Record<string, any>
>(
path: PathParams,
// tslint:disable-next-line no-unnecessary-generics (This generic is meant to be passed explicitly.)
handler1: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler2?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler3?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler4?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler5?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>
): T;
}
export interface IRouterHandler<T, Route extends string = string> {
(
handler1: RequestHandler<RouteParameters<Route>>,
handler2?: RequestHandler<RouteParameters<Route>>,
handler3?: RequestHandler<RouteParameters<Route>>,
handler4?: RequestHandler<RouteParameters<Route>>,
handler5?: RequestHandler<RouteParameters<Route>>
): T;
(
handler1: RequestHandlerParams<RouteParameters<Route>>,
handler2?: RequestHandlerParams<RouteParameters<Route>>,
handler3?: RequestHandlerParams<RouteParameters<Route>>,
handler4?: RequestHandlerParams<RouteParameters<Route>>,
handler5?: RequestHandlerParams<RouteParameters<Route>>
): T;
<
P = RouteParameters<Route>,
ResBody = any,
ReqBody = any,
ReqQuery = ParsedQs,
Locals extends Record<string, any> = Record<string, any>
>(
// tslint:disable-next-line no-unnecessary-generics (This generic is meant to be passed explicitly.)
handler1: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler2?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler3?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler4?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler5?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>
): T;
<
P = RouteParameters<Route>,
ResBody = any,
ReqBody = any,
ReqQuery = ParsedQs,
Locals extends Record<string, any> = Record<string, any>
>(
// tslint:disable-next-line no-unnecessary-generics (This generic is meant to be passed explicitly.)
handler1: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler2?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler3?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler4?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler5?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>
): T;
<
P = ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = ParsedQs,
Locals extends Record<string, any> = Record<string, any>
>(
// tslint:disable-next-line no-unnecessary-generics (This generic is meant to be passed explicitly.)
handler1: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler2?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler3?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler4?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
handler5?: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>
): T;
<
P = ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = ParsedQs,
Locals extends Record<string, any> = Record<string, any>
>(
// tslint:disable-next-line no-unnecessary-generics (This generic is meant to be passed explicitly.)
handler1: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler2?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler3?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler4?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>,
handler5?: RequestHandlerParams<P, ResBody, ReqBody, ReqQuery, Locals>
): T;
}
}
https://www.npmjs.com/package/express-async-handler https://www.npmjs.com/package/express-async-router
It sounds like using of one of the above libraries makes the usage of express-async-handler non-needed. Is it correct?