TypeScript+Express环境下Passport.js谷歌认证后无法获取displayName属性
问题原因分析
两个报错的根因如下:
- 第一个错误
Object is possibly 'undefined':TypeScript默认将req.user定义为可选类型,即使你加了登录校验中间件,TS也无法识别该中间件已经保证了req.user必然存在 - 第二个错误
Property 'displayName' does not exist on type 'User':@types/passport包默认定义的Express.User是空接口,没有包含谷歌OAuth返回的字段定义
解决步骤
步骤1:扩展Express.User类型定义
在你的项目中新建自定义类型声明文件,比如src/@types/express.d.ts,写入以下内容:
declare global { namespace Express { interface User { id: string; displayName: string; name: { familyName: string; givenName: string; }; emails: { value: string; verified: boolean }[]; photos: { value: string }[]; provider: string; _json: Record<string, any>; } } } export {};
然后修改你的tsconfig.json,在compilerOptions配置项中加入自定义类型目录的识别:
{ "compilerOptions": { // 其他原有配置保留 "typeRoots": ["./node_modules/@types", "./src/@types"] } }
注意:路径要和你存放
express.d.ts的实际路径对应
步骤2:解决req.user可能为空的报错
因为你已经通过isLoggedIn中间件保证了访问/profile路由的用户必然已登录,req.user一定存在,所以可以直接用非空断言操作符!告诉TypeScript无需做空值校验:
修改你的路由代码:
app.get('/profile' ,isLoggedIn, (req: Request, res: Response)=> { res.send(`welcome ${req.user!.displayName}`) console.log(req.user!.displayName) })
如果不想用断言,也可以用可选链操作符?.:req.user?.displayName,效果完全一致。
可选优化:给isLoggedIn中间件加上TypeScript类型
修改middleware.ts代码,补充类型定义避免后续其他类型报错:
import { Request, Response, NextFunction } from 'express'; const isLoggedIn = (req: Request, res: Response, next: NextFunction): void => { if (req.user) { next(); } else { res.status(401).send('Not Logged In'); } }; export default isLoggedIn;
内容的提问来源于stack exchange,提问作者udhay r
相关产品推荐
相关产品推荐

