如何为fetch()返回值指定类型?解决TypeScript类型不安全问题
修复TypeScript中fetch请求的ESLint不安全赋值错误
你遇到的问题核心是res.json()默认返回any类型,直接赋值给Activity类型变量时,TypeScript和ESLint无法确认返回数据的结构是否完全匹配,因此触发不安全赋值警告。下面提供几种不同场景下的修复方案:
方案1:使用类型断言(快速解决,无运行时校验)
直接通过类型断言告诉TypeScript,API返回的JSON结构符合Activity类型,快速消除ESLint警告:
type Activity = { activity: string type: string participants: number price: number link: string key: string accessibility: number } async function fetchOne(): Promise<Activity> { const url = "https://www.boredapi.com/api/activity" // 给res.json()添加类型断言 const res = await fetch(url).then(res => res.json() as Activity) return res }
注意:这种方式仅在编译阶段做类型提示,没有运行时校验,如果API返回的结构和Activity不匹配,运行时仍可能出现异常。
方案2:添加运行时类型守卫(最安全)
编写一个类型守卫函数,在运行时校验返回数据的结构,既满足TypeScript类型检查,又能避免异常数据导致的问题:
type Activity = { activity: string type: string participants: number price: number link: string key: string accessibility: number } // 类型守卫函数:校验数据是否符合Activity结构 function isActivity(data: unknown): data is Activity { return ( typeof data === 'object' && data !== null && 'activity' in data && typeof (data as Activity).activity === 'string' && 'type' in data && typeof (data as Activity).type === 'string' && 'participants' in data && typeof (data as Activity).participants === 'number' && 'price' in data && typeof (data as Activity).price === 'number' && 'link' in data && typeof (data as Activity).link === 'string' && 'key' in data && typeof (data as Activity).key === 'string' && 'accessibility' in data && typeof (data as Activity).accessibility === 'number' ) } async function fetchOne(): Promise<Activity> { const url = "https://www.boredapi.com/api/activity" const rawData = await fetch(url).then(res => res.json()) // 校验不通过则抛出错误 if (!isActivity(rawData)) { throw new Error('API返回数据结构不符合预期') } return rawData }
方案3:封装泛型fetch工具函数(复用性高)
如果有多个API请求需要做类型校验,可以封装一个通用的泛型工具函数,减少重复代码:
type Activity = { activity: string type: string participants: number price: number link: string key: string accessibility: number } // 泛型工具函数:接收URL和类型守卫,返回符合类型的结果 async function fetchAndValidate<T>(url: string, validator: (data: unknown) => data is T): Promise<T> { const response = await fetch(url) const rawData = await response.json() if (!validator(rawData)) { throw new Error('数据结构校验失败') } return rawData } // 复用工具函数请求Activity数据 async function fetchOne(): Promise<Activity> { const url = "https://www.boredapi.com/api/activity" return fetchAndValidate(url, (data): data is Activity => { return ( typeof data === 'object' && data !== null && 'activity' in data && typeof (data as Activity).activity === 'string' && 'type' in data && typeof (data as Activity).type === 'string' && 'participants' in data && typeof (data as Activity).participants === 'number' && 'price' in data && typeof (data as Activity).price === 'number' && 'link' in data && typeof (data as Activity).link === 'string' && 'key' in data && typeof (data as Activity).key === 'string' && 'accessibility' in data && typeof (data as Activity).accessibility === 'number' ) }) }
内容的提问来源于stack exchange,提问作者Nicolas S.Xu
相关产品推荐
相关产品推荐

