如何及何时正确使用Handler与Handlers类型?
关于Fresh框架中Handler和Handlers类型的正确用法
基础区别
Handler:单函数形式的处理器,会捕获所有HTTP请求方法,适合需要统一处理所有请求类型的场景。Handlers:对象形式的处理器,每个属性对应一个HTTP方法(如GET/POST/PUT),仅处理对应方法的请求,适合按请求类型拆分逻辑的场景。
类型定义参考:
export type Handler<T = any, State = Record<string, unknown>> = ( req: Request, ctx: FreshContext<State, T>, ) => Response | Promise<Response>; export type Handlers<T = any, State = Record<string, unknown>> = { [K in router.KnownMethod]?: Handler<T, State>; };
泛型参数 <T, State> 的实际含义
这两个参数和处理器返回的Response类型无关,而是绑定到FreshContext的两个核心属性:
T:约束ctx.data的类型,即传递给页面组件的数据类型。如果你的页面组件需要接收特定结构的数据,通过T可以让ctx.data获得类型提示,避免类型错误。State:约束ctx.state的类型,用于在中间件和处理器之间共享请求上下文状态(如用户认证信息、请求追踪ID等)。默认类型为Record<string, unknown>,可自定义更具体的结构来规范状态数据。
正确用法示例
假设页面组件需要接收{ title: string; content: string }类型的数据,同时要在ctx.state中存储用户ID:
// 定义数据类型和状态类型 type ArticleData = { title: string; content: string }; type RequestState = { userId: number }; // Handlers对象形式(仅处理GET/POST请求) export const handler: Handlers<ArticleData, RequestState> = { async GET(_req, ctx) { // ctx.data 自动推导为 ArticleData 类型 ctx.data = { title: "Fresh框架教程", content: "Handler和Handlers类型详解" }; // ctx.state 自动推导为 RequestState 类型 ctx.state.userId = 456; const resp = await ctx.render(); resp.headers.set("X-Author-Id", ctx.state.userId.toString()); return resp; }, async POST(req, ctx) { // 处理POST请求逻辑 return new Response("文章创建成功", { status: 201 }); } }; // Handler单函数形式(处理所有HTTP方法) export const handler: Handler<ArticleData, RequestState> = async (req, ctx) => { if (req.method === "GET") { ctx.data = { title: "Fresh框架教程", content: "Handler和Handlers类型详解" }; ctx.state.userId = 456; return ctx.render(); } else if (req.method === "POST") { return new Response("文章创建成功", { status: 201 }); } return new Response("方法不支持", { status: 405 }); };
关于测试代码无报错的说明
你测试的Handlers<number>代码没有报错,是因为T对应的ctx.data在处理器中未被使用,TypeScript不会强制校验未使用的泛型参数。但这种用法不符合设计意图,应该根据实际需要传递给页面组件的数据类型来设置T,才能发挥类型系统的作用。
内容的提问来源于stack exchange,提问作者Ooker
相关产品推荐
相关产品推荐

