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

如何使用TypeScript为Fetch实现强类型的参数与返回值?

TypeScript实现强类型自定义fetch函数

完全可以通过TypeScript的泛型特性实现这个需求,核心思路是给endpoint定义泛型类型,关联请求体和响应数据的类型,再让myfetch函数基于这些泛型参数做类型校验和推断。

步骤1:定义泛型Endpoint接口

先创建一个泛型接口,用来绑定每个接口的请求体类型、响应类型和HTTP方法:

interface Endpoint<RequestBody = unknown, ResponseData = unknown, Method extends string = string> {
  url: string;
  method: Method;
}

步骤2:定义业务类型与具体Endpoint

根据业务需求定义请求体和响应类型,并创建带泛型约束的endpoint实例:

// 业务响应类型
interface ResponseData {
  status: 'success' | 'error';
}

// 业务请求体类型
interface RequestBody {
  foo: string;
  bar: number;
}

// 关联RequestBody与ResponseData的endpoint
const endpoint: Endpoint<RequestBody, ResponseData, 'get'> = {
  url: '/endpointurl/',
  method: 'get',
};

步骤3:实现强类型myfetch函数

编写泛型函数,根据传入的endpoint自动校验请求体类型,并推断返回值类型:

async function myfetch<Req, Res>(
  endpoint: Endpoint<Req, Res>,
  body?: Req
): Promise<Res> {
  const fetchOptions: RequestInit = {
    method: endpoint.method,
    headers: body ? { 'Content-Type': 'application/json' } : undefined,
    body: body ? JSON.stringify(body) : undefined,
  };

  const response = await fetch(endpoint.url, fetchOptions);
  // 可根据实际情况添加错误处理,比如判断response.ok
  return response.json() as Promise<Res>;
}

步骤4:调用与类型校验

调用myfetch时,TypeScript会自动校验请求体的结构和类型,返回值也会被推断为对应的ResponseData类型:

// 正确调用:请求体符合RequestBody类型
const data = await myfetch(endpoint, { foo: "hello", bar: 42 });
// data自动推断为ResponseData类型,可以直接访问status属性
console.log(data.status);

// 错误调用会触发TypeScript报错:比如bar传字符串
// await myfetch(endpoint, { foo: "hello", bar: "42" });
// 错误调用会触发TypeScript报错:缺少bar字段
// await myfetch(endpoint, { foo: "hello" });

进阶优化:按HTTP方法约束请求体

如果需要更严谨的校验(比如GET方法不允许传请求体,POST必须传),可以通过条件类型实现:

type HttpMethod = 'get' | 'post' | 'put' | 'delete';

// 根据HTTP方法判断是否需要请求体
type RequiresBody<Method extends HttpMethod> = Method extends 'post' | 'put' ? true : false;

async function myfetch<Req, Res, Method extends HttpMethod>(
  endpoint: Endpoint<Req, Res, Method>,
  // 条件类型:需要请求体的方法必须传body,否则可选
  ...args: RequiresBody<Method> extends true ? [body: Req] : [body?: Req]
): Promise<Res> {
  const body = args[0];
  // 后续实现同之前的fetch逻辑
  const fetchOptions: RequestInit = {
    method: endpoint.method,
    headers: body ? { 'Content-Type': 'application/json' } : undefined,
    body: body ? JSON.stringify(body) : undefined,
  };

  const response = await fetch(endpoint.url, fetchOptions);
  return response.json() as Promise<Res>;
}

// POST类型的endpoint必须传请求体
const postEndpoint: Endpoint<RequestBody, ResponseData, 'post'> = {
  url: '/post-endpoint/',
  method: 'post',
};
// 正确调用
await myfetch(postEndpoint, { foo: "hello", bar: 42 });
// 不传body会直接触发TypeScript报错
// await myfetch(postEndpoint);

这种方案完全基于TypeScript的原生类型系统,不需要额外依赖,就能实现请求体和响应数据的强类型校验,在开发阶段提前发现类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:27:23