基于函数参数为Axios返回值定义条件类型的TypeScript问题
基于函数参数为Axios返回值定义条件类型的TypeScript问题
嘿,我看你在写axiosGet工具函数的时候遇到了TypeScript类型推断的问题——当params里没有paginate时,取r.data.data会报错对吧?这是因为你还没把paginate的存在与否和Axios返回值的类型结构关联起来,咱们一步步来解决它。
先把你提供的代码片段放出来方便参考:
export const axiosGet = async <TData>({ url, params = {}, onDone, onError }: TypeAxiosArgs<TData>) => { try { const r = await axios.get<TypeAxiosData<TData, typeof params.paginate>>(url, { params }) let ret if (params?.paginate) { ret = r.data } else { ret = r.data.data // <--- causing typescript to scream, check below } // 省略后续逻辑... } catch (err) { // 错误处理... } }
问题根源
当前的TypeAxiosData类型没有根据paginate的取值做条件分支,TypeScript没办法确定r.data到底是直接的TData,还是包含data属性的对象,所以会在r.data.data这里抛出类型错误。
解决方案:用条件类型关联参数与返回值结构
我们需要修改类型定义,让TypeScript能根据params.paginate的取值,自动推断Axios返回值的结构。
第一步:完善参数与返回值的类型定义
// 定义参数类型,明确paginate是可选布尔值,同时保留其他自定义参数 type TypeAxiosArgs<TData, TPaginate extends boolean = false> = { url: string; params?: { paginate?: TPaginate } & Record<string, unknown>; onDone?: (data: TData) => void; onError?: (error: unknown) => void; }; // 根据paginate的取值,定义Axios返回的data结构 type TypeAxiosData<TData, TPaginate> = TPaginate extends true ? TData // 当paginate为true时,返回值data直接是TData类型 : { data: TData }; // 当paginate不存在或为false时,返回值data是包含data属性的对象
第二步:修改函数逻辑,让类型推断生效
import axios from 'axios'; export const axiosGet = async <TData, TPaginate extends boolean = false>({ url, params = {}, onDone, onError }: TypeAxiosArgs<TData, TPaginate>) => { try { // 这里TypeScript会根据TPaginate的取值,自动匹配TypeAxiosData的结构 const r = await axios.get<TypeAxiosData<TData, TPaginate>>(url, { params }); let ret: TData; if (params.paginate) { ret = r.data; // 此时r.data的类型是TData,完全匹配 } else { ret = r.data.data; // 此时r.data的类型是{ data: TData },取data属性不会报错 } onDone?.(ret); return ret; } catch (error) { onError?.(error); throw error; } };
为什么这样能解决问题?
我们把paginate的类型作为泛型参数TPaginate传入函数,TypeScript会在调用函数时自动捕获params.paginate的实际取值(true/false/undefined),然后通过TypeAxiosData的条件类型,精准推断出Axios返回值的结构,自然就不会在取值时抛出类型错误了。
比如当你这样调用函数时:
// TypeScript自动推断返回值是User[]类型 axiosGet<User[]>({ url: '/users', params: { paginate: true } }); // TypeScript自动推断返回值是User类型 axiosGet<User>({ url: '/users/1' });
备注:内容来源于stack exchange,提问作者K i
相关产品推荐
相关产品推荐

