使用TypeScript在Express.js登录端点实现JWT遇类型错误求助
Hey Greg, let's break down the issues in your code step by step, covering both the TypeScript errors and logical bugs:
The error happens because TypeScript can't guarantee process.env.JWT_SECRET exists—it could be undefined if the environment variable isn't loaded properly. Here's how to fix it:
- First, use the imported
JWT_SECRET(from../util/secrets) instead of directly accessingprocess.env.JWT_SECRET—this also solves your "defined but never used" warning. - Ensure your
secrets.tsfile properly validates the environment variable to eliminate theundefinedrisk:// ../util/secrets.ts import dotenv from 'dotenv'; dotenv.config(); export const JWT_SECRET = process.env.JWT_SECRET; // Add a guard to fail early if the secret is missing if (!JWT_SECRET) { throw new Error('JWT_SECRET is not defined in your environment variables'); } - Then in your login function, replace
process.env.JWT_SECRETwith the importedJWT_SECRET:const token = JsonWebToken.sign({ userId: user._id }, JWT_SECRET);
If TypeScript still flags it, you can use a non-null assertion (JWT_SECRET!) since we already validated its existence in the secrets file.
This is straightforward: you imported JWT_SECRET but never referenced it in your code. Replacing all uses of process.env.JWT_SECRET with the imported variable will make the warning disappear immediately.
logInUser Function Your login function has several unreachable code paths and incorrect Mongoose usage:
- Token generation is unreachable: In your
thencallback, youreturn userbefore reaching the token creation code—this code will never run. - Incorrect
Users.findOnecall: Mongoose'sfindOneexpects a query object, not just a value. UseUsers.findOne({ email })instead ofUsers.findOne(email). - Mixed async/await and
then: Stick to async/await for cleaner, more readable code. - Duplicate response attempts: You send responses without
return, which can cause "headers already sent" errors.
Here's the cleaned-up version:
export const logInUser = async (req: Request, res: Response, next: NextFunction) => { try { const { email, password } = req.body; // Validate required fields first if (!email || !password) { return next(new BadRequestError('Email and password are required')); } const user = await UserService.findUserByEmail(email); if (!user) { return next(new NotFoundError('Email not found')); } const isPasswordValid = await bcrypt.compare(password, user.password); if (!isPasswordValid) { return next(new BadRequestError('Incorrect password')); } // Generate token with only necessary user data (avoid storing full user objects) const token = JsonWebToken.sign( { userId: user._id, email: user.email }, JWT_SECRET! ); return res.status(200).json({ user: { id: user._id, email: user.email }, token, message: 'Log in successfully' }); } catch (error) { next(new InternalServerError('Failed to process login', error)); } };
register Function's Catch Block Your catch block has a nonsensical check: you're comparing the password to the email with bcrypt.compareSync, which serves no purpose. Replace it with a simple error pass-through to your error-handling middleware:
catch (error) { next(new InternalServerError('Failed to register user', error)); }
内容的提问来源于stack exchange,提问作者Greg

