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
相关产品推荐
相关产品推荐

