I'm trying to extend the Request
interface of Express
as:
import express, { Request, Response } from 'express';
interface IRequest extends Request {
user: {
id: string;
}
}
const router = express.Router();
router.get('/', auth, async (req: IRequest, res: Response) => {
try {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch (e) {
console.error((e as Error).message);
res.status(500).send('Server Error');
}
});
but I got the following error:
No overload matches this call. Overload 1 of 3, '(path: PathParams, ...handlers: RequestHandler<ParamsDictionary, any, any, ParsedQs>[]): Router', gave the following error. Argument of type '(req: IRequest, res: Response) => Promise' is not assignable to parameter of type 'RequestHandler<ParamsDictionary, any, any, ParsedQs>'. Types of parameters 'req' and 'req' are incompatible. Property 'user' is missing in type 'Request<ParamsDictionary, any, any, ParsedQs>' but required in type 'IRequest'. Overload 2 of 3, '(path: PathParams, ...handlers: RequestHandlerParams<ParamsDictionary, any, any, ParsedQs>[]): Router', gave the following error. Argument of type '(req: IRequest, res: Response) => Promise' is not assignable to parameter of type 'RequestHandlerParams<ParamsDictionary, any, any, ParsedQs>'. Type '(req: IRequest, res: Response) => Promise' is not assignable to type 'RequestHandler<ParamsDictionary, any, any, ParsedQs>'.ts(2769)
Typescript will not let you, because even if you typed it this way:
router.get('/', auth, async (req: IRequest, res: Response) => {
Typescript will still just assume that express will emit a Request
and not an IRequest
.
However, since you are probably monkey-patching the request object, you can use declaration merging to basically augment's Express' internal request object:
https://www.typescriptlang.org/docs/handbook/declaration-merging.html
If you don't want to globally make this change to Request
, you could also use a assertion to make sure that it really was an IRequest
:
router.get('/', auth, async (req: request, res: Response) => {
try {
assertIRequest(req);
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch (e) {
console.error((e as Error).message);
res.status(500).send('Server Error');
}
});
function assertIRequest(req: Request|IRequest): asserts req is IRequest {
if (!req?.user?.id) throw new Error('Request was not an IRequest');
}