如何避免在Fastify AutoLoad中丢失Zod类型提供器泛型
如何避免在Fastify AutoLoad中丢失Zod类型提供器泛型
我前阵子在Fastify项目里踩了个实打实的坑——明明主文件里已经用withTypeProvider<ZodTypeProvider>()给Fastify实例加上了Zod类型支持,结果用fastify-autoload自动加载routes目录下的路由文件时,所有类型提示直接“蒸发”,请求参数、响应的类型推断全失效,写代码全靠盲敲,别提多闹心了!
折腾了好一会儿,终于摸出几个靠谱的解决办法,分享给你:
方法一:给路由文件的Fastify实例手动指定类型
这是最直接的路子,在每个路由插件里,明确给传入的Fastify实例标注带Zod类型提供器的类型:
import type { FastifyInstance } from 'fastify'; import type { ZodTypeProvider } from 'fastify-type-provider-zod'; import z from 'zod'; export default async function testRoute(fastify: FastifyInstance<any, any, any, ZodTypeProvider>) { fastify.get('/user', { schema: { querystring: z.object({ userId: z.string().uuid(), }), }, }, async (request) => { // 这里request.query.userId会立刻出现正确的类型提示 return { userId: request.query.userId }; }); }
唯一的小缺点是每个路由文件都要重复写类型导入和声明,适合路由不多的小型项目。
方法二:全局声明默认类型提供器
如果项目路由比较多,不想每个文件都重复写类型,试试全局声明的方式。在项目里新建一个类型声明文件(比如src/types/fastify.d.ts),把Fastify实例的默认类型提供器改成Zod的:
import 'fastify'; import type { ZodTypeProvider } from 'fastify-type-provider-zod'; declare module 'fastify' { // 覆盖FastifyInstance的第四个泛型参数默认值为ZodTypeProvider interface FastifyInstance< HttpRequest = FastifyRequest, HttpResponse = FastifyReply, Logger = FastifyLoggerInstance, TypeProvider = ZodTypeProvider, // 这里替换成Zod类型提供器 > extends FastifyBaseLogger<Logger> {} }
写完之后,整个项目里的FastifyInstance都会默认带上ZodTypeProvider的泛型支持,路由文件里直接用就行,不用再手动指定类型,省心到飞起!
方法三:复用主实例的类型定义
还有一种更清晰的方式,就是把主文件里带Zod类型的Fastify实例类型导出,然后在所有路由文件里导入复用:
首先在主文件(比如src/index.ts)里导出实例类型:
import Fastify from 'fastify'; import { ZodTypeProvider } from 'fastify-type-provider-zod'; import AutoLoad from 'fastify-autoload'; import path from 'path'; // 创建带Zod类型的Fastify实例 const fastify = Fastify().withTypeProvider<ZodTypeProvider>(); // 导出这个实例的类型,供路由文件使用 export type AppFastifyInstance = typeof fastify; // 注册自动加载插件 fastify.register(AutoLoad, { dir: path.join(__dirname, 'routes'), }); fastify.listen({ port: 3000 }, (err) => { if (err) throw err; console.log('服务启动在3000端口'); });
然后在路由文件里导入这个类型:
import type { AppFastifyInstance } from '../index'; import z from 'zod'; export default async function userRoute(fastify: AppFastifyInstance) { fastify.post('/user/create', { schema: { body: z.object({ name: z.string().min(2), age: z.number().int().min(18), }), }, }, async (request) => { // request.body的类型会被自动推断,完全不用手动写接口 return { code: 200, data: request.body }; }); }
这种方式的好处是,主实例的类型一旦修改,所有路由文件都会同步更新,类型一致性拉满,大型项目用这个最稳妥。
以上三种方法都能解决AutoLoad丢失Zod泛型的问题,你可以根据自己项目的规模和习惯来选~
内容来源于stack exchange
相关产品推荐
相关产品推荐

