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

Typescript整合passport等库时的类型合并错误求助

TypeScript中Passport类型声明合并失效问题排查与解决

我在TypeScript中使用passport、passport-local和express-session,已安装@types/passport、@types/express-session、@types/passport-local及@types/express依赖,计划用connect-redis存储会话。目前遇到两个类型错误:

  • Property 'emailVerified' does not exist on type 'User'
  • Property 'id' does not exist on type 'User'

尝试用声明合并解决但无效,以下是我的相关代码文件:

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "typeRoots": ["./node_modules/@types"]
  },
  "include": ["src/**/*"]
}

src/@types/express/index.d.ts

declare namespace Express {
  interface User {
    id: string;
    emailVerified: boolean;
  }
}

passport.ts

import passport from 'passport';
import { Strategy as LocalStrategy } from 'passport-local';
import UserModel from '../models/user';

passport.use(
  new LocalStrategy(async (username, password, done) => {
    try {
      const user = await UserModel.findOne({ username });
      if (!user) return done(null, false);
      const isValid = await user.comparePassword(password);
      if (!isValid) return done(null, false);
      return done(null, user);
    } catch (err) {
      return done(err);
    }
  })
);

passport.serializeUser((user, done) => {
  done(null, user.id); // 报错:Property 'id' does not exist on type 'User'
});

passport.deserializeUser(async (id, done) => {
  try {
    const user = await UserModel.findById(id);
    done(null, user);
  } catch (err) {
    done(err);
  }
});

export default passport;

auth.controller.ts

import { Request, Response } from 'express';

export const getProfile = (req: Request, res: Response) => {
  // 报错:Property 'emailVerified' does not exist on type 'User'
  if (req.user?.emailVerified) {
    res.json(req.user);
  } else {
    res.status(403).json({ message: 'Email not verified' });
  }
};

问题原因

  1. tsconfig类型路径配置缺失:默认typeRoots只包含node_modules/@types,TypeScript无法识别自定义的src/@types目录下的声明文件。
  2. 声明合并语法不规范:自定义Express.User时未用global命名空间包裹,导致无法正确合并内置类型。
  3. Passport序列化/反序列化未指定类型:未明确user参数的类型,TypeScript无法关联到自定义的User类型。

解决方法

1. 修正tsconfig.json的typeRoots配置

添加自定义类型目录到typeRoots,确保TypeScript能识别:

{
  "compilerOptions": {
    // 其他配置不变
    "typeRoots": ["./src/@types", "./node_modules/@types"]
  }
}

2. 调整自定义声明文件的写法

修改src/@types/express/index.d.ts,用global命名空间包裹并导出空对象:

declare global {
  namespace Express {
    interface User {
      id: string;
      emailVerified: boolean;
      // 补充你需要的其他用户属性
    }
  }
}

// 必须导出空对象,标记为模块
export {};

3. 为Passport的序列化/反序列化指定类型

在passport.ts中明确user的类型为Express.User:

passport.serializeUser((user: Express.User, done) => {
  done(null, user.id);
});

passport.deserializeUser(async (id: string, done) => {
  try {
    const user = await UserModel.findById(id);
    done(null, user as Express.User); // 若模型返回类型不匹配,可断言类型
  } catch (err) {
    done(err);
  }
});

4. 验证类型关联

重启TypeScript服务(或编辑器的TS语言服务),检查错误是否消失。如果仍有问题,确认:

  • 自定义声明文件的路径正确(src/@types/express/index.d.ts是标准路径)
  • 所有@types依赖版本与对应库版本兼容,可尝试重新安装依赖:
rm -rf node_modules package-lock.json
npm install

内容的提问来源于stack exchange,提问作者PirateApp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 18:25:38