TypeScript中使用function.apply调用Axios时传递泛型的方法
解决方案
你不需要移除封装的requestWrapper,通过以下方式可以给它添加泛型支持,同时保留对Axios方法的动态调用能力:
思路1:适配Axios方法参数,直接调用泛型方法
Axios的get/post等核心方法本身就是泛型函数,我们可以让requestWrapper作为泛型函数,根据HTTP方法的参数差异直接调用对应方法并传递泛型参数:
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; // 限定支持的HTTP方法,避免传入无效方法名 type HttpMethod = 'get' | 'delete' | 'post' | 'put' | 'patch'; /** * 泛型请求封装函数 * @template T 响应数据的类型 * @param method HTTP请求方法 * @param url 请求地址 * @param dataOrConfig 请求体(仅post/put/patch用)或请求配置 * @param config 请求配置(仅post/put/patch用) * @returns 带类型化响应的Promise */ function requestWrapper<T = any>( method: HttpMethod, url: string, dataOrConfig?: any, config?: AxiosRequestConfig ): Promise<AxiosResponse<T>> { // 针对带请求体的方法,传递url + data + config if (['post', 'put', 'patch'].includes(method)) { return axios[method]<T>(url, dataOrConfig, config); } // 针对无请求体的方法,传递url + config return axios[method]<T>(url, dataOrConfig as AxiosRequestConfig); } // 使用示例:定义响应数据类型 interface User { id: number; name: string; email: string; } // GET请求,响应数据为User数组 requestWrapper<User[]>('get', '/api/users').then(res => { // res.data自动推断为User[]类型,支持类型提示 console.log(res.data[0].name); }); // POST请求,响应数据为单个User requestWrapper<User>('post', '/api/users', { name: 'Alice', email: 'alice@example.com' }).then(res => { console.log(res.data.id); });
思路2:保留apply调用,通过类型断言绑定泛型
如果你的requestWrapper依赖apply处理复杂参数逻辑,可以通过类型断言将Axios方法转为泛型函数,再指定泛型参数:
import axios, { AxiosResponse } from 'axios'; // 提取Axios支持的泛型方法类型 type AxiosGenericMethod = <T>(...args: any[]) => Promise<AxiosResponse<T>>; // 限定支持的HTTP方法 type HttpMethod = keyof Pick<typeof axios, 'get' | 'delete' | 'post' | 'put' | 'patch'>; function requestWrapper<T = any>( method: HttpMethod, ...args: Parameters<typeof axios[HttpMethod]> ): Promise<AxiosResponse<T>> { // 将Axios方法断言为泛型方法,再指定T const genericMethod = axios[method] as AxiosGenericMethod; // 用apply调用(也可以直接用扩展运算符...args) return genericMethod.apply(axios, args) as Promise<AxiosResponse<T>>; } // 使用示例 interface Article { id: string; title: string; } requestWrapper<Article>('get', '/api/articles/1').then(res => { console.log(res.data.title); });
为什么不建议移除wrapper?
封装requestWrapper的核心价值是统一处理请求逻辑(比如全局错误拦截、请求头注入、日志上报等),如果直接在业务代码中调用Axios,后续要更换HTTP客户端(比如换成fetch、Ky)时,需要修改所有业务代码,违背了封装的初衷。通过上述改造,既保留了封装的优势,又获得了TypeScript的类型安全支持。
内容的提问来源于stack exchange,提问作者Jesús Imitola
相关产品推荐
相关产品推荐

