Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to type `request.query` 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'.
  Type 'undefined' is not assignable to type 'string'.

Setup:

import { Request, Response, Router } from 'express';

const router = Router();

function getHandler(request: Request, response: Response) {
  const { query } = request;

  query.foo; // string | QueryString.ParsedQs | string[] | QueryString.ParsedQs[] | undefined

}

router.route('/')
  .get(getHandler)

Is there a proper way to type request.query without casting?

like image 790
marcobiedermann Avatar asked Aug 22 '20 16:08

marcobiedermann


People also ask

How to modify a query in express request?

Modifying the query in Express.Request is somewhat more tricky, because Express uses types from express-serve-static-core , which in turn Express doesn’t expose. So the only way to get hold of the proper types is to import { Query } from 'express-static-serve-core'; . The solution is to do:

Can I override a query type in typescript?

Look at e.g. typescriptlang.org/docs/handbook/…. Overriding the query type won't change the runtime behaviour (it can't, types and TS don't exist at runtime). The solution is to use generics in the following manner.

Is the type 'request' generic?

I'm trying to use this approach and getting the error: Type 'Request' is not generic. Tested on @types/express 4.17.11. Works great! BTW, it would be better to use Request<unknown, unknown, unknown, Foo>. Otherwise, the ESLint will give error: Don't use {} as a type. {} actually means "any non-nullish value".

What is the difference between request and reqquery?

The Request is a generic which accepts additional definitions: interface Request< P = core.ParamsDictionary, ResBody = any, ReqBody = any, ReqQuery = core.Query, Locals extends Record<string, any> = Record<string, any> > extends core.Request<P, ResBody, ReqBody, ReqQuery, Locals> {}


Video Answer


5 Answers

The solution is to use generics in the following manner.

const router = Router();

interface Foo {
    foo: string;
}

function getHandler(request: Request<{}, {}, {}, Foo>, response: Response) {
  const { query } = request;

  query.foo;

}

router.route('/')
  .get(getHandler)
like image 171
p4t Avatar answered Oct 23 '22 08:10

p4t


I like to use the following approach in my projects.

  const { url } = req.query;
  
  if (typeof url !== "string") {
    throw new ServerError("Query param 'url' has to be of type string", 400);
  }

After checking the type TypeScript won't complain any more for this scope.

like image 5
Matthis Kohli Avatar answered Oct 23 '22 08:10

Matthis Kohli


you can do it like this :-

interface Query {
   param1:string;
   param2:string;
};

function getHandler(request: Request, response: Response) {
   const {param1,param2} = request.query as unknown as Query;
}
like image 5
Amresh Kumar Avatar answered Oct 23 '22 10:10

Amresh Kumar


Definition

The Request is a generic which accepts additional definitions:

interface Request<
  P = core.ParamsDictionary,
  ResBody = any,
  ReqBody = any,
  ReqQuery = core.Query,
  Locals extends Record<string, any> = Record<string, any>
> extends core.Request<P, ResBody, ReqBody, ReqQuery, Locals> {}

Source: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express/index.d.ts#L112-L117

Example

interface RequestParams {}

interface ResponseBody {}

interface RequestBody {}

interface RequestQuery {
  foo: string;
}

function getHandler(
  request: Request<RequestParams, ResponseBody, RequestBody, RequestQuery>,
  response: Response
) {
  const { query } = request;

  query.foo; // string
}
like image 3
marcobiedermann Avatar answered Oct 23 '22 08:10

marcobiedermann


In my humble opinion the simpler and straight forward method is to use the StringConstructor. Any downside of this method in this particular situation is welcome in the comments.

var String: StringConstructor (value?: any) => string Allows manipulation and formatting of text strings and determination and location of substrings within strings.

import { Request, Response, Router } from 'express';

const router = Router();

function getHandler(request: Request, response: Response) {
  const { foo } = request.query;

  String(foo) // string
}

router.route('/').get(getHandler)
like image 1
Lianel Avatar answered Oct 23 '22 09:10

Lianel