How to add Typescript definitions to Express req & res
You can use ES6 style named imports to import only the interfaces you need, rather than import * as express from 'express'
which would include express itself.
First, make sure you have installed the type definitions for express (npm install -D @types/express
).
Example:
// middleware/authCheck.tsimport { Request, Response, NextFunction } from 'express';export const authCheckMiddleware = (req: Request, res: Response, next: NextFunction) => { ...};// server.tsimport { authCheckMiddleware } from './middleware/authCheck';app.use('/api', authCheckMiddleware);
Currently using TypeScript 2.3.4 and @types/express 4.0.36.
It can be daunting to type the arguments every time you need to write middleware functions so you can just type the whole function directly too.
npm i @types/express --save-dev ("@types/express": "^4.17.0")
After installing typings..
// This can be shortened..import { Request, Response, NextFunction } from 'express';export const myMiddleware = (req: Request, res: Response, next: NextFunction) => { ...};// to this..import { RequestHandler } from 'express';export const myMiddleware: RequestHandler = (req, res, next) => { ...};// or in case it handles the error objectimport { ErrorRequestHandler } from 'express';export const myMiddleware: ErrorRequestHandler = (err, req, res, next) => { ...};
What I've found is that you can leverage TypeScript generics very effectively to create a wrapper around the Express Request
type.
You can declare something that looks similar to this in an interfaces file/folder:
import { NextFunction, Request, Response } from 'express';type TypedRequest< ReqBody = Record<string, unknown>, QueryString = Record<string, unknown>> = Request< Record<string, unknown>, Record<string, unknown>, Partial<ReqBody>, Partial<QueryString>>;export type ExpressMiddleware< ReqBody = Record<string, unknown>, Res = Record<string, unknown>, QueryString = Record<string, unknown>> = ( req: TypedRequest<ReqBody, QueryString>, res: Response<Res>, next: NextFunction) => Promise<void> | void;
TypedRequest
is effectively a wrapper around Express' Request
interface, and populates it with the generics that you pass it, but are also optional (note Record<string, unknown>
. It then also applies a Partial
around each of the generics (you probably want to make this a DeepPartial
instead)
ExpressMiddleware
takes in 3 optional generics ReqBody
Res
and QueryString
. These are used to construct a function signature that resembles what middlewares/controllers should look like.
The above then allows you to strongly type & consume as follows:
import { ExpressMiddleware } from '../interfaces/ExpressMiddleware';type Req = { email: string; password: string };type Res = { message: string };export const signupUser: ExpressMiddleware<Req, Res> = async (req, res) => { /* strongly typed `req.body`. yay autocomplete 🎉 */ res.json({ message: 'you have signed up' }) // strongly typed response obj};
I hope this helps someone. It's made a massive difference to my Express experience.