You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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:

1. Fix the "string | undefined" Type Error for JWT Secret

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 accessing process.env.JWT_SECRET—this also solves your "defined but never used" warning.
  • Ensure your secrets.ts file properly validates the environment variable to eliminate the undefined risk:
    // ../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_SECRET with the imported JWT_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.

2. Resolve the "JWT_SECRET is defined but never used" Warning

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.

3. Fix Critical Logic Bugs in the logInUser Function

Your login function has several unreachable code paths and incorrect Mongoose usage:

  • Token generation is unreachable: In your then callback, you return user before reaching the token creation code—this code will never run.
  • Incorrect Users.findOne call: Mongoose's findOne expects a query object, not just a value. Use Users.findOne({ email }) instead of Users.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));
  }
};
4. Fix the 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 14:02:31