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

TypeScript中如何校验fetch后response.json()的返回类型并抛出异常?

解决TypeScript中Fetch API返回数据的类型校验问题

你当前的核心问题是:as Promise<TResponse>只是编译时的类型断言,完全没有运行时校验能力——哪怕后端返回的数据缺字段、类型不匹配,TypeScript也无法在运行时识别,只会把错误数据强行当成你指定的类型返回。要实现「不符合类型就抛异常」的需求,必须添加运行时类型校验逻辑。


1. 编写类型守卫函数

先为需要校验的类型(比如ISession)编写类型守卫函数,用来在运行时检查数据是否符合预期结构:

/*
 * 类型定义
 */
interface ICredentials {
  username: string;
  password: string;
}

interface ISession {
  token: string;
}

// 校验数据是否符合ISession类型的类型守卫
function isSession(data: unknown): data is ISession {
  // 先判断是否为非空对象
  if (typeof data !== 'object' || data === null) {
    return false;
  }
  // 强制转为对象后,检查指定字段的类型
  const session = data as ISession;
  return typeof session.token === 'string';
}

如果后续有更多类型需要校验,只需为每个类型编写对应的守卫函数即可。


2. 改造API的Post方法

修改api.post函数,新增校验函数参数,在拿到返回数据后执行校验,不符合则抛出异常:

/*
 * 改造后的API请求函数
 */
const api = {
  post: async <TBody, TResponse>(
    url: string,
    bodyParams?: TBody,
    validator: (data: unknown) => data is TResponse // 新增校验函数参数
  ) => {
    try {
      const response = await fetch(`https://reqres.in/api/${url}`, {
        method: "POST",
        body: JSON.stringify(bodyParams),
        headers: {
          "Content-Type": "application/json",
        },
      });

      // 先处理HTTP状态码非2xx的情况
      if (!response.ok) {
        throw new Error(`请求失败,状态码: ${response.status}`);
      }

      const rawData = await response.json();
      // 执行类型校验,不通过则抛异常
      if (!validator(rawData)) {
        throw new Error(`返回数据结构错误: ${JSON.stringify(rawData)}`);
      }

      // 校验通过后,TypeScript会自动推断rawData为TResponse类型
      return rawData;
    } catch (e) {
      console.error("API请求出错:", e);
      // 抛出错误让上层调用者处理
      throw e;
    }
  },
};

3. 修改登录函数的调用逻辑

调用api.post时传入对应的类型守卫函数,完成校验:

/*
 * 登录函数
 */
async login(data: ICredentials) {
  try {
    return await api.post<ICredentials, ISession>("users", data, isSession);
  } catch (e) {
    console.error("登录失败:", e);
    // 这里可以添加错误提示、页面跳转等业务逻辑
    throw e;
  }
}

扩展:通用校验工具(可选)

如果有大量类型需要校验,手写每个守卫函数会重复冗余,可以封装一个通用校验工具:

// 通用对象类型校验生成器
function createValidator<T>(schema: Record<keyof T, string>) {
  return function (data: unknown): data is T {
    if (typeof data !== 'object' || data === null) return false;
    const obj = data as T;
    for (const key in schema) {
      if (typeof obj[key] !== schema[key]) {
        return false;
      }
    }
    return true;
  };
}

// 用工具快速生成ISession的校验函数
const isSession = createValidator<ISession>({ token: 'string' });
// 生成ICredentials的校验函数
const isCredentials = createValidator<ICredentials>({ username: 'string', password: 'string' });

内容的提问来源于stack exchange,提问作者skyrix-lang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 11:42:47