如何实现基于Zod的通用Fetch函数:校验查询参数与JSON返回结果
解决Zod Schema参数的类型标注问题
你的核心问题是泛型参数缺少Zod Schema的类型约束,导致TypeScript无法识别querySchema.parse和responseSchema.parse这些方法,同时z.infer的使用方式也有误(不能用typeof TQuerySchema,因为TQuerySchema本身就是泛型类型参数,不是值类型)。
修正后的代码方案
我们需要将泛型参数约束为Zod的Schema类型,让TypeScript明确这两个参数是具备Zod校验能力的Schema对象:
import { z } from 'zod'; // 泛型约束为ZodSchema,确保参数拥有parse方法 const zodFetch = async < TQuerySchema extends z.ZodSchema, TResponseSchema extends z.ZodSchema >( url: string, querySchema: TQuerySchema, query: z.infer<TQuerySchema>, responseSchema: TResponseSchema ): Promise<z.infer<TResponseSchema>> => { const response = await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json;charset=UTF-8', }, body: JSON.stringify({ query: querySchema.parse(query), }), }); return responseSchema.parse(await response.json()); }; const test = async () => { const fooSchema = z.number(); const barSchema = z.string(); // 此时response会被正确推断为string类型 const response = await zodFetch('https://foobar', fooSchema, 1, barSchema); console.log(response); }; void test();
关键变化说明
- 给泛型
TQuerySchema和TResponseSchema添加extends z.ZodSchema约束,告诉TypeScript这两个参数必须是Zod的Schema实例,确保parse方法存在且类型安全。 - 移除了
typeof操作符,直接使用z.infer<TQuerySchema>获取Schema对应的类型,因为TQuerySchema已经是Schema类型本身,不是值的类型。 - 调用
zodFetch时,TypeScript会自动根据传入的Schema推断出query参数的类型和返回值类型,比如示例中query必须是number,返回值response是string。
另一种更简洁的写法
如果你更关注最终的类型而非Schema本身,可以直接将泛型定义为Schema对应的类型,让TypeScript自动推断Schema:
import { z } from 'zod'; const zodFetch = async <TQuery, TResponse>( url: string, querySchema: z.ZodType<TQuery>, query: TQuery, responseSchema: z.ZodType<TResponse> ): Promise<TResponse> => { const response = await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json;charset=UTF-8', }, body: JSON.stringify({ query: querySchema.parse(query), }), }); return responseSchema.parse(await response.json()); };
这种写法更直观,泛型TQuery和TResponse直接对应校验后的数据类型,TypeScript会自动匹配传入的Schema是否符合该类型。
内容的提问来源于stack exchange,提问作者doberkofler
相关产品推荐
相关产品推荐

