如何在Next.js中为NextApiRequest添加自定义类型?
Next.js JWT验证中间件TypeScript类型错误修复
问题背景
我在Next.js中使用TypeScript开发了一个JWT验证中间件,用于校验API请求的用户是否持有有效JWT令牌。代码功能正常运行,但存在TypeScript类型错误需要修复。
原中间件代码
import { verifyJwtToken } from "../utils/verifyJwtToken.js"; import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next' import cookie from "cookie" const authMiddleware = (handler: NextApiHandler) => async (req: NextApiRequest, res: NextApiResponse) => { try { const cookies = cookie.parse(req.headers.cookie || '') const token = cookies.token const verifiedToken = await verifyJwtToken(token) if (!verifiedToken) { throw new Error('You have no access to do it.') } const userId = Number(verifiedToken.id) // 调用API路由处理器并传入添加了userId的请求对象 return handler({ ...req, userId }, res) } catch (err) { console.error(err) res.status(401).json({ message: 'You have no access to do it.' }) } } export default authMiddleware;
类型错误信息
Argument of type '{ userId: number; query: Partial<{ [key: string]: string | string[]; }>; cookies: Partial<{ [key: string]: string; }>; body: any; env: Env; preview?: boolean | undefined; ... 35 more ...; eventNames(): (string | symbol)[]; }' is not assignable to parameter of type 'NextApiRequest'. Object literal may only specify known properties, and 'userId' does not exist in type 'NextApiRequest'.ts(2345)
尝试过的无效方案
我创建了继承自NextApiRequest的自定义接口,试图通过修改中间件的req参数类型来解决问题,但并未生效:
// CustomNextApiRequest.ts import { NextApiRequest } from 'next' interface CustomNextApiRequest extends NextApiRequest { userId: number } export default CustomNextApiRequest;
修改中间件的req参数类型:
import CustomNextApiRequest from './CustomNextApiRequest'; const authMiddleware = (handler: NextApiHandler) => async (req: CustomNextApiRequest, res: NextApiResponse) => { // ...原代码逻辑 }
中间件使用示例
async function addCommentHandler(req: NextApiRequest, res: NextApiResponse) { // 业务逻辑代码... } export default authMiddleware(addCommentHandler);
正确解决方案
问题根源在于:中间件接收的NextApiHandler仅支持标准NextApiRequest类型,但我们传入了带有自定义userId属性的请求对象。需要调整中间件的类型定义,让它兼容处理自定义请求的处理器,同时在调用时正确做类型断言。
步骤1:定义自定义请求接口
在项目中创建类型文件(比如types/CustomNextApiRequest.ts):
import { NextApiRequest } from 'next'; export interface CustomNextApiRequest extends NextApiRequest { userId: number; }
步骤2:修改中间件的类型定义
调整中间件,使其接受处理CustomNextApiRequest的处理器,同时保持中间件本身对外暴露标准的NextApiHandler类型:
import { verifyJwtToken } from "../utils/verifyJwtToken.js"; import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'; import cookie from "cookie"; import { CustomNextApiRequest } from './types/CustomNextApiRequest'; // 定义中间件类型:接收处理自定义请求的处理器,返回标准NextApiHandler const authMiddleware = (handler: (req: CustomNextApiRequest, res: NextApiResponse) => Promise<void> | void): NextApiHandler => { return async (req: NextApiRequest, res: NextApiResponse) => { try { const cookies = cookie.parse(req.headers.cookie || ''); const token = cookies.token; const verifiedToken = await verifyJwtToken(token); if (!verifiedToken) { throw new Error('You have no access to do it.'); } const userId = Number(verifiedToken.id); // 使用类型断言将扩展后的请求对象转为CustomNextApiRequest return handler({ ...req, userId } as CustomNextApiRequest, res); } catch (err) { console.error(err); res.status(401).json({ message: 'You have no access to do it.' }); } }; }; export default authMiddleware;
步骤3:更新业务处理器的请求类型
在使用中间件的API路由中,将处理器的req参数类型改为CustomNextApiRequest,这样就能获得userId的类型提示:
import { NextApiResponse } from 'next'; import { CustomNextApiRequest } from './types/CustomNextApiRequest'; import authMiddleware from './authMiddleware'; async function addCommentHandler(req: CustomNextApiRequest, res: NextApiResponse) { // 可以直接使用req.userId,且有类型提示 console.log('当前用户ID:', req.userId); // 业务逻辑代码... } export default authMiddleware(addCommentHandler);
内容的提问来源于stack exchange,提问作者periakteon
相关产品推荐
相关产品推荐

