How to cast req.query parameters in Express using Typescript

I'm running an express.js application using TypeScript. Every time I try to process request.query.foo I get the following error:

Argument of type 'string | ParsedQs | string[] | ParsedQs[] | undefined' is not assignable to parameter of type 'string'.

Setup:

import { Request, Response } from 'express';

function bar(request: Request, response: Response) {
  const foo: string = request.query.foo; //marked as error
}

I read on the documentation of Express that you can set a configuration called "query parser" that when set to "simple" will always parse the query parameters as a string

The problem is that Typescript still thinks that something other than string or undefined may come and I can't seem to find a way to override the Request interface, I can only extend it.

Is there any way to override the Request interface? is there something wrong in my approach?

Upvotes: 17

Views: 21828

Answers (4)

Aaron Aguilar
Aaron Aguilar

Reputation: 41

Late to the party and not the best but you can try

const name: string = req.query.name as string;

just fail save the code by null check

Upvotes: 4

JoelBonetR
JoelBonetR

Reputation: 1572

Workarounds I ended up using depending on the situation:

1: Example extending the Request type.

import { Request } from 'express';
import { IncomingHttpHeaders } from 'http';

interface iExtendedRequest extends Request {
  headers: IncomingHttpHeaders & { authorization: string };
}

// Use the extended request interface as entry param
const getAuth = (req: iExtendedRequest): string => req.headers?.authorization;

2: Example using double casting:

type Users = {
  id: number;
  name: string;
};

const getUsers = (req: Request) => {
  // Cast req.query as unknown
  const query = req.query as unknown;
  // if allows us to cast it as our type
  const user = query as Users;
  // and then apply destructuring
  const { id, name } = user;

  id // number
  name // string
};

Upvotes: 0

Helmer Barcos
Helmer Barcos

Reputation: 2076

You could define the types that you will expect on the ReqBody, ReqQuery and the other generics of Request type. For the Response you should also be able to define other types and pass it as generics. Don't forget to install @types/express by running npm install -D @types/express

Then you could create other SomeHandlerRequest and others ReqDictionary, ReqBody, ReqQuery and ResBody for each specific case.

import { Request } from 'express'

// if you need define other response generics
// import { Request, Response } from 'express'


// This types could be exported from other file. Then you should import them
type ReqDictionary = {}
type ReqBody = { foo1 ?: string }
type ReqQuery = { foo2 ?: string }
type ResBody = { foo3 ?: string }

type SomeHandlerRequest = Request<ReqDictionary, ResBody, ReqBody, ReqQuery>

const myCustomHandler = (req: SomeHandlerRequest, res) : void => {
   const { foo1 } = req.body
   const { foo2  } = req.query

   // Your custom logic ..... for example...
   if (foo1) {
      console.log("foo1 value = ", foo1)
   }
   if (foo2) {
      console.log("foo2 value = ", foo2)
   }

   res.status(200).json({ foo3 : "it works" })
}

Upvotes: 15

Tom Carchrae
Tom Carchrae

Reputation: 6486

if you're like me, and due to upgrading a dependency, all of a sudden you had lots of errors, you may want a quick fix (until you go through and type all your requests)

so, simply specify the type of req to any and you're done. back to the old untyped method.

eg,

router.get('/',(req : any, res, next) => { 
    const { foo } = req.query;
    console.log('foo is a string',foo);
 });

Converting an untyped application to a typed one is not a trivial or quick thing. sometimes, you need to upgrade a dependency and get something working again, and have to leave the exercise of adding strict types for another day.

replace all dialog

Upvotes: -6

Related Questions