Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend express request for passport's user parameter

I'm using Passport to handle authentication with an Express application. This sets the user on the Express response. I'm using TypeScript, so setting the request type to Request in the route definitions will error because the user object does not exist on the Express Request. There are numerous questions about extending the request, either by declaration merging or extending the interface but these cause another error. My file looks like this:

import { Router, Request, Response }  from 'express'
import { User as CustomUser } from './user'

interface IRequest extends Request {
  user: CustomUser
}

const router: Router = Router()

router.get('/', requiresLogin, (req: IRequest, res: Response) => {
  console.log(req.user)
  res.sendStatus(204)
})

But now I'm getting the following TypeScript on the express callback:

Argument of type '(req: IRequest, res: Response) => void' is not assignable to parameter of type 'RequestHandlerParams'. Type '(req: IRequest, res: Response) => void' is not assignable to type '(RequestHandler | ErrorRequestHandler)[]'. Property 'includes' is missing in type '(req: IRequest, res: Response) => void'.

I've recently upgraded to TypeScript v2.8.3, and never had the problem previously.

like image 244
Geraint Anderson Avatar asked May 21 '18 11:05

Geraint Anderson


1 Answers

I just had a similar problem and solved it like this:

import { Router, Request, Response } from 'express';
import { User as CustomUser } from './user';

const router: Router = Router();

router.get('/', requiresLogin, (req: Request, res: Response) => {
  console.log(req.user as CustomUser);
  res.sendStatus(204);
});

Instead of augmenting the Express.js Request type, I simply told TypeScript that the req.user is going to be of type CustomUser using a type assertion. This seems like the exact scenario that the reference in the docs "Sometimes you’ll end up in a situation where you’ll know more about a value than TypeScript does."

https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions

Now I know what you're thinking. "What if there is no user? Doesn't this defeat the purpose of Typescript?". Well, let's looks at this. If you are using Passport.js, you should not get this far without a user. This code should be somewhere inside your Passport config:

if (!user) {
  /** Set status code to Unauthorized */
  res.status(401);

  return next(err);
}

As for defeating Typescript... maybe you're right. If someone has a better answer for this scenario though, I am all ears.

like image 81
Borduhh Avatar answered Nov 18 '22 03:11

Borduhh