You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化TypeScript泛型函数中Zod解析JSON响应的实现?

问题与解决方案

问题描述

我有一个用于请求不同URL并获取JSON响应的函数,希望使用Zod对响应进行验证。请问是否存在比示例更优的实现方式,无需在每次调用函数时传入Zod Schema?同时能否避免使用as T类型断言?

原示例代码:

import * as z from "zod";

// Zod 校验 Schema
const MyResponse = z.strictObject({
  key: z.string()
});

// TypeScript 类型
type MyResponse = z.infer<typeof MyResponse>;

// 带泛型的请求函数
async function request<T>(schema: z.ZodObject, url: string): Promise<T> {
  const response = await fetch(url);

  return schema.parse(await response.json()) /*as T*/;
}

// 调用函数
await request<MyResponse>(MyResponse, '/');

优化方案

方案1:自动从Schema推断类型,消除手动泛型与类型断言

调整泛型参数,让它直接关联Zod Schema的类型,TypeScript会自动推导返回值类型,无需手动指定泛型或使用as T:

import * as z from "zod";

const MyResponse = z.strictObject({
  key: z.string()
});

// 泛型绑定到Zod Schema,自动推断返回类型
async function request<Schema extends z.ZodTypeAny>(
  schema: Schema,
  url: string
): Promise<z.infer<Schema>> {
  const response = await fetch(url);
  const data = await response.json();
  return schema.parse(data); // 无需断言,类型自动匹配
}

// 调用时仅需传入Schema和URL,类型自动推导
const result = await request(MyResponse, '/');
// result 类型自动为 { key: string }

方案2:预定义绑定Schema的专用请求函数

如果某些接口的Schema固定,可以提前创建绑定好Schema的请求函数,后续调用仅需传入URL:

import * as z from "zod";

const MyResponse = z.strictObject({
  key: z.string()
});

// 通用基础请求函数
async function requestWithSchema<Schema extends z.ZodTypeAny>(
  schema: Schema,
  url: string
): Promise<z.infer<Schema>> {
  const response = await fetch(url);
  const data = await response.json();
  return schema.parse(data);
}

// 预定义绑定MyResponse的请求函数
const requestMyResponse = (url: string) => requestWithSchema(MyResponse, url);

// 调用时只需传URL
const result = await requestMyResponse('/');

方案3:工厂函数批量生成专用请求器

如果有多个固定Schema的接口,用工厂函数批量生成绑定对应Schema的请求函数,彻底避免重复传Schema:

import * as z from "zod";

// 请求函数工厂:传入Schema,返回绑定该Schema的请求函数
function createRequester<Schema extends z.ZodTypeAny>(schema: Schema) {
  return async (url: string): Promise<z.infer<Schema>> => {
    const response = await fetch(url);
    const data = await response.json();
    return schema.parse(data);
  };
}

// 生成不同Schema的请求函数
const MyResponse = z.strictObject({ key: z.string() });
const requestMyResponse = createRequester(MyResponse);

const AnotherResponse = z.strictObject({ id: z.number() });
const requestAnotherResponse = createRequester(AnotherResponse);

// 调用示例
const myResult = await requestMyResponse('/');
const anotherResult = await requestAnotherResponse('/another');

以上方案均无需每次调用传Schema,且完全避免了as T类型断言,同时保留了完整的类型安全校验。

内容的提问来源于stack exchange,提问作者dennis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 14:55:04