why request.query is not 'any' anymore? express request.query typescript error - node.js

after npm i this is the error that i get if i try to pass query params to a function that expects string:
Argument of type 'string | Query | (string | Query)[]' is not assignable to parameter of type 'string'.
Type 'Query' is not assignable to type 'string'.ts(2345)
import express from "express";
async function getProductsImagesByShopEvent(req: express.Request, res: express.Response,
next: express.NextFunction) {
try {
const params = req.query;
if (!params || !params.shopEventId)
throw new CustomError("params are missing in /business/getProductsImagesByShopEvent", 400, "params are missing");
const shopEvent = new ShopEvent();
const events = await shopEvent.getProductsImagesByShopEvent(params.shopEventId);
res.json(events);
}
catch (error) {
next(error);
}
}
async getProductsImagesByShopEvent(shopEventId: string) {
}
the error is in params.shopEventId..
if i add: const params = (req.query as any); it works

This makes express more strict in typings. You have to add types.
const shopEventId: string = req.query.shopEventId as string

Related

How to mock in express with Typescript and Mocha library

How to mock 'Request' in Mocha using express with Typescript?
Current solution is following:
describe("Authorization middleware", () => {
it("Fails when no authorization header", () => {
const req = {
get: () => {
return null;
},
};
expect(isAuth(req as Request, {}, () => {}));
});
});
I have got an error Conversion of type '{ get: () => null; }' to type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Is forcing 'unknown' type the only solution to this problem?
You can use node-mocks-http package to create the mockups of the request and response objects for express routing functions.
E.g.
import { expect } from "chai";
import {Request, Response} from 'express';
import httpMocks from 'node-mocks-http';
const isAuth = (req: Request, res: Response) => {
// your code under test
}
describe("Authorization middleware", () => {
it("Fails when no authorization header", () => {
const req = httpMocks.createRequest();
const res = httpMocks.createResponse()
expect(isAuth(req, res));
});
});
The return value of httpMocks.createRequest() API is MockRequest type, its generic parameter is constrained by express Request type. The Request type is a subset of the MockRequest type, so it matches the Request type.

How to add custom properties on the Request object in Express + TypeScript?

I am trying to add a user object as a custom property in the Request object of Express, but I got the following error:
Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'
This is my code in a middleware function:
// Authenticate person/user through the database.
const person = new Person(username, password);
const user = await authenticate(person); // ORM => read DB
if (!user) {
return res
.status(401)
.json({ message: "Invalid Authentication Credentials" });
}
// attach user to request object
req.user = user; // <= HERE is my problem
next();
How I can add this custom property to the request?
I think the standard way to do this is by extending the Response interface exported by Express and declaring your Data as being part of the Locals generic type.
In #types/express/index.d.ts # line 127:
export interface Response<ResBody = any, Locals extends Record<string, any> = Record<string, any>>
extends core.Response<ResBody, Locals> {}
You can therefore create a Type that will be used in lieu of the default value for the Locals generic like so:
import type { Response, Request, NextFunction } from 'express';
import type { User } from './models'; // Or wherever it is, obviously.
type MyLocals = { user?: User; };
type MyResponse = Response<any, MyLocals>
// Using the `MyResponse` type is as simple as setting the type of `res` to be `MyResponse`, e.g.:
async function doSomeWork (req: Request, res: MyResponse, next: NextFunction): Promise<void> {
console.log(res.locals.user); // undefined | User
}
There are some other ways to achieve this, as well, but this is what I have always done when using Typescript + Express.

Error no overload matches this call( Typescript + Express + JWT)

I'm learning typescript and I'm trying to build a middleware function that would use jsonwebtoken to manage the rights of the users.
I've first setup a verify token middleware function and I've created an interface that extends the Request interface of Express in this function. By doing this I'm able to attach a users property on the request object that I can use on the jwt.verify callback function. Everything works fine for this part. I don't get any error
But then, when I add the verify function to my router I get the following
error code in the router ts file:
No overload matches this call.
The last overload gave the following error.
Argument of type '(req: IGetUserAuthInfoRequest, res: Response, next: NextFunction) => Response<any, Record<string, any>> | undefined' is not assignable to parameter of type 'RequestHandlerParams<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
When I remove the callback function in the jwt.verify function and I set the req parameter type to Request, the error disappears but it's not the expected behaviour since I'm not able to access anymore the user parameter of the request object.
Here is the code for my verify function:
import { RequestHandler, Request, NextFunction,Response } from 'express';
import * as jwt from 'jsonwebtoken';
interface IGetUserAuthInfoRequest extends Request {
users: jwt.JwtPayload | undefined // or any other type
}
// Check if jsonwebtoken is valid
const verify = (req:IGetUserAuthInfoRequest, res:Response, next:NextFunction) =>{
const authHeader = req.headers.token
if (authHeader && typeof authHeader === 'string') {
const token = authHeader.split(" ")[1]
jwt.verify(token, `${process.env.ACCESS_TOKEN_SECRET_KEY}`, (err, users)=> {
if (err) {res.status(403).json("Token is not valid")}
req.users = users
next()
})
} else {
return res.status(401).json("Not authenticated")
}
}
Here is my code for my router where I get the error:
import { Router } from "express";
import verify from "../verifyToken";
import { updateUser } from "../controllers/userController";
const router = Router();
router.put("/:id", verify,updateUser)
export default router
Finally, I've tried to update the req parameter type in the verify function by setting it to Request like the code below:
import { RequestHandler, Request, NextFunction,Response } from 'express';
import * as jwt from 'jsonwebtoken';
// Check if jsonwebtoken is valid
const verify = (req:Request, res:Response, next:NextFunction) =>{
const authHeader = req.headers.token
if (authHeader && typeof authHeader === 'string') {
const token = authHeader.split(" ")[1]
jwt.verify(token, `${process.env.ACCESS_TOKEN_SECRET_KEY}`, (err, users)=> {
if (err) {res.status(403).json("Token is not valid")}
req.users = users
next()
})
} else {
return res.status(401).json("Not authenticated")
}
}
export default verify
When I do this change I get another error on the users property saying:
Property 'users' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>
I'm really confuse and I don't understand what I'm doing wrong in my logic.

Fastify Typescript request query

I'm trying to put together a simple endpoint following the Fastify with Typescript docs here:
https://www.fastify.io/docs/v3.1.x/TypeScript/
export default async function foo(fastify: any) {
const MyInstance = new Foo(fastify.db);
app.get<{ Querystring: IQueryString, Headers: IHeaders }>(
"/foo",
async (request: FastifyRequest, reply: FastifyReply) => {
console.log(request.query); // *prints query object*
const { queryObj } = request.query; // *Gives error: Object is of type 'unknown'*
const result = await MyInstance.getFoo(queryObj);
reply.status(200).send(result);
}
);
}
Why do I get the error when I try to access the request.query object and how do I fix it?
By default FastifyRequest.query's type RequestQuerystringDefault maps to unknown because one cannot guess which attributes/type you'll want to set for it.
Should you have a defined type for the query of some request, just define that request type and use it:
type MyRequest = FastifyRequest<{
Querystring: { queryObj: MyQueryObject }
}>
then specify it as the expected request type:
async (request: MyRequest, reply: FastifyReply) => {
const { queryObj } = request.query // Ok
}
If you write the code to look it like Express.js, try that one:
app.get('/foo', async (req: FastifyRequest<{
Params: {
name: string,
};
}>,
rep: FastifyReply,) => {
const name = req.params.name // string
})

Expression of type 'string' can't be used to index type 'Request<ParamsDictionary, any, any, Query>'

I am trying to create a middleware for validating the input data in request.
export function validator(schema: Joi.ObjectSchema, key: string) {
return function (req: Request, res: Response, next: NextFunction): void {
try {
Joi.assert(req[key], schema);
next();
} catch (error) {
console.log(error);
throw new Error(error);
}
};
}
But the req[key] is throwing following error:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Request'.
No index signature with a parameter of type 'string' was found on type 'Request'.
The other solutions that I found to problems similar to this include the interface in their own code. I don't understand why this error is coming and how to solve this?
Also the following code is from the express's type definition file.
interface Request<P extends core.Params = core.ParamsDictionary, ResBody = any, ReqBody = any, ReqQuery = core.Query> extends core.Request<P, ResBody, ReqBody, ReqQuery> { }
What does the above definition mean?
Changing key: string in the definition of validator to key: keyof Request worked.

Resources