I am using Typescript in Node.js. When you use Express middleware, you often transform the Request object. With Typescript, however, we could not track how the Request object was transformed. If you know the middleware that passed before, is there a way to find out the type of the request from it? If not possible in express, I would like to find another framework where it is possible. Is it possible in Nest (https://github.com/kamilmysliwiec/nest)?
Example Code
import { Request, Response, NextFunction } from 'express';
function userMiddleware(req: Request & User, res: Response, next: NextFunction) {
req.user = {
id: 'user_id',
};
next();
}
interface User {
user: {
id: string;
}
}
interface Middleware {
<T>(req: Request & T, res: Response, next: NextFunction): void;
}
class Controller {
middleware = [userMiddleware];
get = new GetMethod(this.middleware);
post = (req: Request /* I don't know exact req type */, res: Response, next: NextFunction) => {
console.log(req.user) // Error!
}
}
class GetMethod {
constructor(middleware: Middleware[]) {
// How to deduce type of req from Middleware array?
}
}
const controller = new Controller();
express.use('/', controller.middleware, controller.post);
I want to extract type information from Middleware list in Controller class.
Express middleware are functions that execute during the lifecycle of a request to the Express server. Each middleware has access to the HTTP request and response for each route (or path) it's attached to. In fact, Express itself is compromised wholly of middleware functions.
Middleware functions in Express are of the following types: Application-level middleware which runs for all routes in an app object. Router level middleware which runs for all routes in a router object. Built-in middleware provided by Express like express.
Router-level middleware works in the same way as application-level middleware, except it is bound to an instance of express.Router() . Load router-level middleware by using the router.use() and router.METHOD() functions.
An Express-based application is a series of middleware function calls. Advantages of using middleware: Middleware can process request objects multiple times before the server works for that request. Middleware can be used to add logging and authentication functionality.
First I think the right interface is
interface User {
id: string;
}
Because they're callbacks they'll receive default Request
that don't have user
in its signature.
Therefore you have 2 options, do a type assertion, or to write a custom declaration. Both a fine if you do them properly.
Type assertion:
interface User {
id: string;
}
const isObject = (value: unknown): value is {[key: string]: unknown} => {
return value && typeof value === 'object';
};
const isReqWithUser = (req: Request): req is Request & {user: User} => {
return isObject(req) && !!req.user;
}
class Controller {
post = (req: Request, res: Response, next: NextFunction) => {
if (isReqWithUser(req)) {
console.log(req.user) // now it works
}
next();
}
}
Custom declaration:
but we need to understand that user not always exist on the request and we should mark it optional.
interface User {
id: string;
}
declare module 'express' {
export interface Request {
user?: User; // adding our custom declaration.
}
}
class Controller {
post = (req: Request, res: Response, next: NextFunction) => {
console.log(req.user) // now it works
next();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With