Reputation: 163
Please help, I am getting this error
src/app/middlewares/authentication.ts:16:17 - error TS2339: Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
16 req.user = user;
I have created the .d.ts file and also included it in tsconfig file. Still I am not able to run this code
Please find attached screenshots
Upvotes: 15
Views: 35281
Reputation: 1
Everything above didn't help for me unfortunately but alternative Solution is to use res.locals
for Storing userId
Instead of attaching userId to req, you can use res.locals
to store it. This is a standard pattern in Express and avoids the complications of extending the Request interface.
Here is why it works
Avoids Modifying req: Since res.locals
is specifically designed for passing data between middleware and routes, it avoids the need to extend Request.
No TypeScript Errors: res.locals
is a free-form object, so TypeScript won't raise errors when adding properties like userId.
I hope I was able to save 2 days of your life =)
Before index.ts
app.get(
"/auth/me",
checkAuth,
async (req: Request, res: Response): Promise<void> => {
try {
const user = await userModel.findOne(req.userId);
console.log(user);
if (!user) {
res.status(404).json({
message: " User not found",
});
return;
}
res.json({
success: true,
// userId: req.userId,
});
} catch (err) {}
}
);
Before CheckAuth.ts
import { NextFunction, Request, Response } from "express";
import jwt from "jsonwebtoken";
interface JwtPayload {
id: string;
}
export default (req: Request, res: Response, next: NextFunction) => {
const token = (req.headers.authorization || "").replace(/Bearer\s?/, "");
if (!token) {
return res.status(403).json({
message: "Authorization header is missing",
});
}
try {
const decoded = jwt.verify(token, "secret123") as JwtPayload;
req.userId = decoded.id; // Assign the userId property
next();
} catch (err) {
res.status(403).json({
message: "Access denied: Invalid or expired token",
});
}
};
After index.ts
app.get(
"/auth/me",
checkAuth,
async (req: Request, res: Response): Promise<void> => {
try {
const userId = res.locals.userId;
if (!userId) {
res.status(401).json({ message: "Unauthorized" });
}
const user = await UserModel.findOne({ _id: userId });
if (!user) {
res.status(404).json({
message: " User not found",
});
return;
}
const userObjectData = user.toObject(); // Convert to plain object
const { passwordHash, ...userData } = userObjectData;
res.json(userData);
} catch (err) {
res.status(500).json({ message: "An error occurred" });
}
}
);
After CheckAuth.ts
import { NextFunction, Request, Response } from "express";
import jwt from "jsonwebtoken";
interface JwtPayload {
id: string;
}
export default (req: Request, res: Response, next: NextFunction) => {
const token = (req.headers.authorization || "").replace(/Bearer\s?/, "");
if (!token) {
res.status(403).json({
message: "Authorization header is missing",
});
return;
} else {
try {
const decoded = jwt.verify(token, "secret123") as JwtPayload;
res.locals.userId = decoded.id;
next();
} catch (err) {
res.status(403).json({
message: "Access denied",
});
}
}
};
Upvotes: 0
Reputation: 1
I did exactly the same thing that all the responses to this post are saying.
But I achieved a solution with a simple command, in addition to the previous solutions
In the script you need to put "--files"
"scripts": { "dev": "ts-node-dev --respawn --env-file=.env --files src/index.ts",
Upvotes: 0
Reputation: 444
src/
- types/
- express/
- index.d.ts
import express from "express";
declare global {
namespace Express {
interface Request {
user?: Record<string,any>
}
}
}
{
"compilerOptions": {
"typeRoots" : ["./src/types", "./node_modules/@types"]
}
}
Upvotes: 41
Reputation: 39
These were the variables I want to use in the Request object. In your /src/types/express/index.d.ts
you should put::
export {}
declare global {
namespace Express {
export interface Request {
idUser?: string
email?: string
username?: string
// extra variables you want to use in req object
}
}
}
In your tsconfig.json
:
{
"compilerOptions": {
// other settings
"typeRoots": ["./src/types", "./node_modules/@types"] // it's important to put first your path file otherwise it won't work
// other settings
}
}
Upvotes: 1
Reputation: 11
Remember to config "typeRoots" in tsconfig.json
{
"compilerOptions":
{
"typeRoots": ["./src/types", "./node_modules/@types"],
}
}
Upvotes: 0
Reputation: 150
A quick walkaround if you are doing a quick prototype or following a tutorial
(req as any).user
NB: Do not use this in a real production app, because it would make your code dirty and it's not scalable.
Upvotes: 0
Reputation: 29
Another way:
import { NextFunction, Request, Response } from 'express';
interface IDecode {
address: string,
role: string,
iat: number,
exp: number
};
interface RequestWithUserRole extends Request {
user?: IDecode,
}
const parseToken = (secret: string) =>
async (req: RequestWithUserRole, res: Response, next: NextFunction) => {
try{
const token = req.headers?.authorization?.split(' ')[1];
// console.log(req.headers?.authorization);
if (!token) {
return res.status(403).json({message: 'Token not found'})
}
const decodedData = <IDecode> jwt.verify(token, secret);
req.user = decodedData;
// console.log(decodedData);
return next();
}
catch(e) {
return res.status(500).json({e})
}
};
Upvotes: 2
Reputation: 107
I was stuck on the same problem earlier. Here is how I solved it.
import * as express from "express"
declare global {
namespace Express {
interface Request {
user? : Record<string,any>
}
}
}
"compilerOptions": {
...other settings,
"typeRoots": ["@types", "node_modules/@types"],
...other settings
}
And that's it. It should works with these changes.
Upvotes: 6