,
+> {
+ // tslint:disable-next-line callable-types (This is extended from and can't extend from a type alias in ts<2.2)
+ (
+ req: Request,
+ res: Response,
+ next: NextFunction,
+ ): void;
+}
+
+export type ErrorRequestHandler<
+ P = ParamsDictionary,
+ ResBody = any,
+ ReqBody = any,
+ ReqQuery = ParsedQs,
+ LocalsObj extends Record = Record,
+> = (
+ err: any,
+ req: Request,
+ res: Response,
+ next: NextFunction,
+) => void;
+
+export type PathParams = string | RegExp | Array;
+
+export type RequestHandlerParams<
+ P = ParamsDictionary,
+ ResBody = any,
+ ReqBody = any,
+ ReqQuery = ParsedQs,
+ LocalsObj extends Record = Record,
+> =
+ | RequestHandler
+ | ErrorRequestHandler
+ | Array | ErrorRequestHandler>;
+
+type RemoveTail = S extends `${infer P}${Tail}` ? P : S;
+type GetRouteParameter = RemoveTail<
+ RemoveTail, `-${string}`>,
+ `.${string}`
+>;
+
+// prettier-ignore
+export type RouteParameters = string extends Route ? ParamsDictionary
+ : Route extends `${string}(${string}` ? ParamsDictionary // TODO: handling for regex parameters
+ : Route extends `${string}:${infer Rest}` ?
+ & (
+ GetRouteParameter extends never ? ParamsDictionary
+ : GetRouteParameter extends `${infer ParamName}?` ? { [P in ParamName]?: string }
+ : { [P in GetRouteParameter]: string }
+ )
+ & (Rest extends `${GetRouteParameter}${infer Next}` ? RouteParameters : unknown)
+ : {};
+
+/* eslint-disable @definitelytyped/no-unnecessary-generics */
+export interface IRouterMatcher<
+ T,
+ Method extends "all" | "get" | "post" | "put" | "delete" | "patch" | "options" | "head" = any,
+> {
+ <
+ Route extends string,
+ P = RouteParameters,
+ ResBody = any,
+ ReqBody = any,
+ ReqQuery = ParsedQs,
+ LocalsObj extends Record = Record,
+ >(
+ // (it's used as the default type parameter for P)
+ path: Route,
+ // (This generic is meant to be passed explicitly.)
+ ...handlers: Array>
+ ): T;
+ <
+ Path extends string,
+ P = RouteParameters,
+ ResBody = any,
+ ReqBody = any,
+ ReqQuery = ParsedQs,
+ LocalsObj extends Record = Record,
+ >(
+ // (it's used as the default type parameter for P)
+ path: Path,
+ // (This generic is meant to be passed explicitly.)
+ ...handlers: Array>
+ ): T;
+ <
+ P = ParamsDictionary,
+ ResBody = any,
+ ReqBody = any,
+ ReqQuery = ParsedQs,
+ LocalsObj extends Record = Record,
+ >(
+ path: PathParams,
+ // (This generic is meant to be passed explicitly.)
+ ...handlers: Array