'What does this error say? Type 'ParsedQs' is not assignable to type 'string'

Hello my problem is I want to use the search query of mongoose. But I want to make a get request using a query. Why is that not possible? I do not understand this error. I am using version 5.10.0 of mongoose. I don't want to do it as a post request and I would not like to use req.body. Can anyone help me?

here my code:

export const searching = (req: Request, res: Response) => {
  Company.find({ $text: { $search: req.query } }).exec((err, docs) => {
    if (docs) {
      res.status(200).json(docs)
    } else {
      console.log(err)
    }
  })
}

my error message:

(property) $search: string
No overload matches this call.
The last overload gave the following error.
Type 'ParsedQs' is not assignable to type 'string'.ts(2769)


Solution 1:[1]

req.query is an object containing request query

So if you send a request to the endpoint like this /?foo=bar&a=123

You can access the query value from

req.query.foo // bar
req.query.a // 123

You are passing query object to the $search, meanwhile you are supposed to pass a string, so it should be

Company.find({ $text: { $search: req.query.yourQueryKey as string } }).exec((err, docs) => {

Better solution is to type your RequestHandler function

import {RequestHandler} from "express";

type Params = {};
type ResBody = {};
type ReqBody = {};
type ReqQuery = {
    query: string;
}

export const searching: RequestHandler<Params, ResBody, ReqBody, ReqQuery> = (req, res) => {
    const query = req.query.query; // string
}

Even better solution: type your RequestHandler function and use a validation library to validate the request query like joi or celebrate

Solution 2:[2]

You are passing req.query to your search and the default Typescript type for req.query is

Request<unknown, unknown, unknown, QueryString.ParsedQs, Record<string, any>>.query: QueryString.ParsedQs 

and if you passed in req.query.searchText the type for that would be

string | QueryString.ParsedQs | string[] | QueryString.ParsedQs[] | undefined

The simple way is already answered here just do

export const searching = (req: Request, res: Response) => { 
const searchText = req.query. searchText as string
  Company.find({ $text: { $search: searchText } }).exec((err, docs) => {
    if (docs) {
      res.status(200).json(docs)
    } else {
      console.log(err)
    }
  })
}

That works but gets sloppy when you have a lot of variables from your query params. In express try out the RequestHandler for your endpoints.

import { RequestHandler } from 'express'

interface QueryTypes {
  searchText: string
  moreSearchText: string
}
export const searching:RequestHandler<unknown, unknown, unknown, QueryTypes > = (req, res) => {
  Company.find({ $text: { $search: req.query } }).exec((err, docs) => {
    if (docs) {
      res.status(200).json(docs)
    } else {
      console.log(err)
    }
  })
}

You can see using the RequestHandler I can pass in a few unknown types and the fourth one I can pass in the query types. I can also remove the Request and Response types to just (req, res) because RequestHandler already types out the handler for us.

You're probably wondering what the 3 previous unknown are and that too in the typescript docs for RequestHandler. Here is the docs.

interface RequestHandler<P = core.ParamsDictionary, ResBody = any, ReqBody = any, ReqQuery = qs.ParsedQs, Locals extends Record<string, any> = Record<string, any>>

Now using RequestHandler. I can type out parameters, body, reqbody or query. Use a combo or skip them using unknown like I did in my example.

This also has the added benefit of giving you type safety so

const test = req.query.test

would highlight a typescript error in vscode for me because 'test' is defined in my QueryTypes interface.

Solution 3:[3]

Adding as any like as below might help you -

Company.find({ $text: { $search: req.query as any} }).exec((err, docs) => {
-------------
-------------
-------------

Solution 4:[4]

req.query is an object that contains all of query parameters you specified in the query.

If your request looks like this

test.com/search/?s=something

something will be stored in req.query.s.

The second option is to use named route parameters. So you can set do this:

Request URL

test.com/search/something

Route

app.get('/search/:search', (req, res) => {
   console.log(req.params.search); // "something". NB use req.params, not req.query
})

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Richard Torcato
Solution 3 Pradeep
Solution 4 F'1