在TypeScript+Express项目中如何让req.user被识别为Prisma的User类型?
我之前在做TS+Express+Prisma项目时,完完全全遇到过和你一模一样的问题!折腾了好几个小时才把这些坑踩平,给你分享几个肯定能解决的办法:
一、先把类型声明文件写对
首先,你的.d.ts文件写法有个小细节要注意:在类型声明文件里导入Prisma的User时,一定要用类型导入(import type),不然TS可能不会正确识别全局扩展的类型。
创建src/types/express.d.ts文件,内容如下:
import type { User } from '@prisma/client'; declare global { namespace Express { interface Request { user?: User; } } }
这里用import type是为了告诉TS这只是类型导入,不会产生任何运行时的代码,避免把这个.d.ts文件变成一个模块(模块里的全局声明有时候会有识别问题)。
二、检查tsconfig.json的配置是否完整
光有类型文件还不够,得确保TS能找到它。你的tsconfig里要同时配置typeRoots和include,缺一不可:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "typeRoots": ["./node_modules/@types", "./src/types"], // 其他配置保持你的原有设置即可 }, "include": [ "src/**/*", "src/types/**/*.d.ts" // 明确包含你的类型声明文件 ] }
我当初就是只配了typeRoots没加include,导致TS一直没读到我的扩展类型。
三、确保控制器里的Request是正确导入的
你要保证在控制器里用的Request是从express原生导入的,而不是其他库的类型:
// 正确的导入方式 import { Request, Response } from 'express'; // 错误示例:不要从其他地方导入Request,比如自定义的未扩展的类型
四、重启一切!
这步看起来傻,但真的很重要:
- 关掉你的dev服务器(比如nodemon、ts-node-dev)
- 重启VS Code的TypeScript语言服务(可以按Ctrl+Shift+P,输入"TypeScript: Restart TS Server")
- 再重新启动dev服务器
TS有时候会缓存旧的类型定义,不重启的话,新的扩展类型根本不会被加载。
五、如果以上都不行,试试自定义Request类型
要是还是没生效,那可以换个思路:直接创建一个扩展了User属性的自定义Request类型,不用全局扩展。
比如在src/types/request.ts里写:
import { Request as ExpressRequest } from 'express'; import type { User } from '@prisma/client'; export type Request = ExpressRequest & { user?: User; };
然后在控制器里导入这个自定义的Request:
// 导入你自定义的Request,而不是express的原生Request import { Request, Response } from '../types/request'; import asyncHandler from '../middleware/asyncHandler'; import ApiError from '../utils/ApiError'; const logout = asyncHandler(async (req: Request, res: Response) => { if (!req.user) { throw new ApiError(404, "request user not exist"); } const userID = req.user.id; // 这里TS会正确识别为User | undefined // ...剩下的逻辑 });
这个方法是我最后实在没办法时用的,亲测有效,相当于绕开了全局类型扩展的坑。
最后再排查一个小细节
确认你已经运行过npx prisma generate,保证@prisma/client里的User类型是最新且存在的。要是Prisma的类型没生成,那你的扩展自然也会失效。
内容来源于stack exchange

