Property 'message' does not exist on type 'ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.ts(2339)? - node.js

Hello I created a custom error middleware handler in my node typescript app
and getting an error that message does not exist on type ErrorRquestHandler
const errorHandler = (
err: ErrorRequestHandler,
_req: Request,
res: Response,
_next: NextFunction
) => {
const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
res.status(statusCode);
res.json({
message: err.message,
stack: err.stack
})
}
I've tried uncommenting "typeRoots" and "types" in my tsconfig.json file and still same error.
What is causing this error?
Thanks

It looks like you have an error handler that is declared correctly but the type of the err parameter is wrong, instead, the const errorHandler itself should be typed with ErrorRequestHandler so the parameters are inferred.
The type ErrorRequestHandler is defined as follows in DefinitelyTyped:
export type ErrorRequestHandler<
P = ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = ParsedQs,
Locals extends Record<string, any> = Record<string, any>
> = (
err: any,
req: Request<P, ResBody, ReqBody, ReqQuery, Locals>,
res: Response<ResBody, Locals>,
next: NextFunction,
) => void;
Suggesting that your code should look as follows:
const errorHandler: ErrorRequestHandler = (
err,
_req,
res,
_next
) => {
const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
res.status(statusCode);
res.json({
message: err.message,
stack: err.stack
})
}
Note that change to const errorHandler to be typed with ErrorRequestHandler meaning you can drop the explicitly typed parameters on the function (unless you have the tsconfig option enabled that requires them). Do note that now err is typed as err: any thanks to ErrorRequestHandler, you should probably test it to ensure it's an error first before using err.message as its also not guaranteed to be a type of Error. The compiler will allow it however as it's typed as any, to be safe I would recommend you test explicitly for errors using the built-in node utility api before making use of properties.
if (isNativeError(err)) {
// use err.message
} else {
// handle unexpected error
// or send generic unknown error response
}

Related

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.

NODE.JS(TYPESCRIPT) Property 'req' does not exist on type 'NodeModule'

I am having issues using this.status and this.req in my subfile
I initialize the route index like this
router.use(response);
my index file is below
import {Request,Response,NextFunction} from 'express'
module.exports = function(req:Request, res:Response, next:NextFunction){
const responseTypes = {
unprocessable: require('./unprocessable')
};
res = {...res, ...responseTypes};
next();
};
here is my unprocessable.ts file
import log from '../logger'
import queue from '../queue'
module.exports = function (data, message) {
log.warn('Sending unprocessable entity response: ', data, message || 'unprocessable entity');
const req = this.req;
const res = this;
// Dump it in the queue
const response = { response: { status: 'error', data: data, message: message ? message : 'unprocessable entity' } };
response.requestId = req.requestId;
queue.add('logResponse', response);
if (data !== undefined && data !== null) {
if (Object.keys(data).length === 0 && JSON.stringify(data) === JSON.stringify({})) {
data = data.toString();
}
}
if (data) {
this.status(422).json({ status: 'error', data: data, message: message ? message : 'unprocessable entity' });
} else {
this.status(422).json({ status: 'error', message: message ? message : 'unprocessable entity' });
}
};
It complains about the following in the unprocessable.ts file
Property 'status' does not exist on type 'NodeModule' if I use this.status
Property 'req' does not exist on type 'NodeModule' if I use this.req
I have no idea how to solve it as I am new to typescript
Typescript does for the most part not know what you refer to when you are using the this keyword.
You can however tell typescript what you mean by this, e.g:
function someFunction(this: object) {
// do something with this
}
In your case, this refers to an object that extends Response from express so what you could do is:
const { Response } = require('express');
interface IModifiedResponse extends Response {
// define your properties here
unprocessable: (data: object, message: string) => void
}
function unprocessable(this: IModifiedResponse, data: object, message: string) {
// use this as in your function
}
However I do not know what this.req refers to as Response does not have a req property. See ExpressJS docs
Hope this answers helps :).

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.

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

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

Resources