I am using the request handler interface to design my controllers. Here is an example
import { RequestHandler } from "express";
//#region GetLoggedInUserInformation
type GetLoggedInUserInformationControllerParams = {};
type GetLoggedInUserInformationControllerBodyRequest = {};
type GetLoggedInUserInformationControllerResponse = {
age: number;
weightKg: number;
heightCm: number;
gender: string;
};
type GetLoggedInUserInformationControllerLinkQuery = {};
export const GetLoggedInUserInformationController: RequestHandler<
GetLoggedInUserInformationControllerParams,
GetLoggedInUserInformationControllerResponse,
GetLoggedInUserInformationControllerBodyRequest,
GetLoggedInUserInformationControllerLinkQuery
> = async (req, res, next) => {
try {
// Controller logic
} catch (e) {
next(e);
}
};
//#endregion
The problem is that i am passing custom variables to the request during the middleware logic. Typescript is always throwing an error when i try to read a variable in the req object. Even after declaring global namespace like below :-
declare namespace Express {
interface Request {
userId : number
}
}
Here is the error when i try to read that variable
Property 'userId' does not exist on type 'Request<GetLoggedInUserInformationControllerParams, GetLoggedInUserInformationControllerResponse, GetLoggedInUserInformationControllerBodyRequest, GetLoggedInUserInformationControllerLinkQuery, Record<...>>'.ts(2339)
I tried to add custom header interface like this :-
export interface ExtendedHeader extends Request {
userId: number;
}
And modify the controller to be like this
export const getLoggedInUserInformationController: RequestHandler<
GetLoggedInUserInformationControllerParams,
GetLoggedInUserInformationControllerResponse,
GetLoggedInUserInformationControllerBodyRequest,
GetLoggedInUserInformationControllerLinkQuery
> = async (req: ExtendedHeader, res, next) => {
try {
const userInformation = await prisma.user.findUnique({
where: { id: req.userId },
});
res.json({ result: true });
} catch (e) {
next(e);
}
};
I get an error on the function initiating line with this info
const getLoggedInUserInformationController: RequestHandler<GetLoggedInUserInformationControllerParams, GetLoggedInUserInformationControllerResponse, GetLoggedInUserInformationControllerBodyRequest, GetLoggedInUserInformationControllerLinkQuery, Record<...>>
Type '(req: ExtendedHeader, res: Response<GetLoggedInUserInformationControllerResponse, Record<string, any>, number>, next: NextFunction) => Promise<...>' is not assignable to type 'RequestHandler<GetLoggedInUserInformationControllerParams, GetLoggedInUserInformationControllerResponse, GetLoggedInUserInformationControllerBodyRequest, GetLoggedInUserInformationControllerLinkQuery, Record<...>>'.
Types of parameters 'req' and 'req' are incompatible.
Property 'userId' is missing in type 'Request<GetLoggedInUserInformationControllerParams, GetLoggedInUserInformationControllerResponse, GetLoggedInUserInformationControllerBodyRequest, GetLoggedInUserInformationControllerLinkQuery, Record<...>>' but required in type 'ExtendedHeader'.ts(2322)
types.ts(4, 3): 'userId' is declared here.
I found the only solution for this is to remove the RequestHandler interface and use the Request Response NextFunction interfaces which coming from express. But there is a lot of controllers that have been designed in that why in our application and i wan't to follow the same procedure with the rest for code readability.
So any idea how i can use RequestHandler interface with extended Request ?