React.js+TypeScript中如何校验fetch API响应的返回类型
Fetch API 运行时响应类型校验实现方案
首先明确核心前提:TypeScript 的类型定义仅在编译阶段生效,运行时会被完全擦除,因此仅给 fetch 响应标注类型属于编译时的类型断言,不会触发任何运行时校验。要实现响应不匹配预设类型就抛出错误的效果,必须额外搭配运行时校验逻辑。
实现思路
- 编写与TS类型对应的运行时校验规则,通常用类型守卫函数实现
- 封装通用 fetch 处理方法,拿到原始响应数据后先执行校验逻辑
- 校验不通过直接抛出错误,校验通过则返回带正确类型标注的数据
代码改造示例
第一步:编写类型守卫校验函数
针对你定义的TodoData类型,编写对应的校验逻辑:
interface TodoData { id: number, userId: number, title: string, completed: boolean, } // 单个TodoData结构校验 function isTodoData(data: unknown): data is TodoData { return ( typeof data === 'object' && data !== null && 'id' in data && typeof (data as TodoData).id === 'number' && 'userId' in data && typeof (data as TodoData).userId === 'number' && 'title' in data && typeof (data as TodoData).title === 'string' && 'completed' in data && typeof (data as TodoData).completed === 'boolean' ) } // TodoData数组结构校验 function isTodoDataArray(data: unknown): data is TodoData[] { return Array.isArray(data) && data.every(isTodoData) }
第二步:封装带校验的通用fetch方法
async function fetchWithValidate<T>( url: string, validator: (data: unknown) => data is T ): Promise<T> { const res = await fetch(url) // 先校验请求状态 if (!res.ok) throw new Error(`请求异常,状态码:${res.status}`) const rawResponse = await res.json() // 执行类型校验 if (!validator(rawResponse)) { throw new Error('响应数据结构不符合预设类型要求') } return rawResponse }
第三步:改造原有业务代码
import React, { useEffect, useState } from 'react'; import './App.css'; type Test = { name: string; age?: number; } const App: React.FC<Test> = ({name, age}) => { // 给state标注正确类型 const [todos, setTodos] = useState<TodoData[] | null>(null); useEffect(() => { const fetchData = async () => { try { const todoData = await fetchWithValidate( 'https://jsonplaceholder.typicode.com/todos', isTodoDataArray ); setTodos(todoData); } catch (error) { // 可统一处理请求错误或类型校验错误 console.error(error); } } fetchData(); },[]) return ( <div className="App"> <p>Hello {name} your age is {age? age: "not given here."}</p> </div> ); } export default App;
优化方案
如果校验的类型结构比较复杂,不想手写大量类型守卫代码,可以使用Schema校验类库自动生成类型定义和校验逻辑,减少重复代码量。
内容的提问来源于stack exchange,提问作者MarcL
相关产品推荐
相关产品推荐

