Axios TypeScript 类型系统详解:模块解析、错误 Type Guard 与泛型化请求配置(axios) 📅 发布时间:2026/9/7 19:07:34 👁 浏览次数: Axios TypeScript 类型系统详解模块解析、错误 Type Guard 与泛型化请求配置axios【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios本文为 axiosPromise based HTTP client for the browser and node.jsTypeScript 支持的技术指南围绕其官方文档 docs/fr/pages/advanced/type-script.md 的核心内容展开。读完本篇你将掌握axios 在 ESM/CJS 双模块格式下的 TypeScript 解析配置要点、如何用isAxiosError/isCancel对catch中的unknown错误做类型收窄以及如何通过AxiosRequestConfigD, P双泛型、可调用AxiosInstance、Symbol 键模块增强等机制实现请求/响应数据的端到端类型安全。类型定义文件的发布方式axios 通过 npm 包内置 TypeScript 类型声明ESM 入口对应 index.d.tsCommonJS 入口对应 index.d.cts因此无论使用哪种模块格式类型检查与编辑器补全开箱即用。这一点可以直接在 package.json 中得到验证顶层字段types: index.d.ts与typings: ./index.d.ts声明了默认类型入口exports字段中通过require: ./index.d.cts、default: ./index.d.ts的types条件把类型声明按模块解析方式精确路由到对应文件运行时入口同样分离require指向./dist/node/axios.cjs默认指向 ESM 的./index.js。正是这种「ESM 默认导出 CJSmodule.exports」的双发布形态引出了下面这组配置注意事项。模块解析的配置要点由于 axios 同时发布 ESM 默认导出和 CJS 的module.exportsTypeScript 项目需要留意以下解析细节以下配置要求以文档为准推荐 TypeScript 4.7你的场景建议配置推荐方案moduleResolution: node16由module: node16隐含启用要求 TypeScript ≥ 4.7项目本身使用 ESM通常无需额外调整现有配置即可正确解析编译到 CJS 且无法使用node16解析必须开启esModuleInterop否则默认导入的互操作类型会报错用 TypeScript 检查 CJS 格式的 JavaScript 代码唯一可行的选项是moduleResolution: node16其原理对应exports映射node16解析器会依据你的文件是 ESM 还是 CJS 来选择index.d.ts/index.d.cts并正确处理默认导出互操作而旧的nodenode10解析器只能看到types顶层字段无法感知条件导出所以才需要esModuleInterop兜底。错误类型守卫isAxiosError 与 isCancel在catch块中error的静态类型是unknown。axios 提供两个类型守卫函数安全收窄类型其声明位于 index.d.tsexport function isAxiosErrorT any, D any, P any( payload: any ): payload is AxiosErrorT, D, P; export function isCancelT any, D any, P any(value: any): value is CanceledErrorT, D, P;使用axios.isAxiosError收窄之后即可在完全类型安全的状态下访问error.response、error.config、error.code等 axios 专属属性import axios from axios; let user: User | null null; try { const { data } await axios.get(/user?ID12345); user data.userDetails; } catch (error) { if (axios.isAxiosError(error)) { handleAxiosError(error); } else { handleUnexpectedError(error); } }运行时实现非常简单且可靠见 lib/helpers/isAxiosError.jsexport default function isAxiosError(payload) { return utils.isObject(payload) payload.isAxiosError true; }它检查对象上是否存在isAxiosError true标记位而该标记正对应 index.d.ts 中AxiosError类的isAxiosError: boolean属性——类型系统与运行时行为严格一致。对于请求取消例如使用AbortController的signal场景用axios.isCancelT()将错误收窄为CanceledErrorTconst controller new AbortController(); try { await axios.getUser(/user?ID12345, { signal: controller.signal }); } catch (error) { if (axios.isCancelUser(error)) { handleCancellation(error); } }从类型声明看index.d.tsCanceledErrorT, D, P继承自AxiosErrorT, D, P带有name: CanceledError与可选的__CANCEL__标记因此收窄后可以访问与AxiosError相同的全部属性。AxiosError上还以静态常量形式列出了常见的错误码ERR_NETWORK、ETIMEDOUT、ECONNABORTED等见 index.d.ts可用于error.code的枚举式比对。请求数据与查询参数的双泛型D 与 PAxiosRequestConfigD any, P any的两个泛型参数分别承载请求体数据D与查询参数P自定义的参数序列化器也能拿到同样的P。该接口定义在 index.d.tsexport interface AxiosRequestConfigD any, P any { // ...省略其余配置项... params?: P; paramsSerializer?: | ParamsSerializerOptionsunknown extends P ? Recordstring, any : P | CustomParamsSerializerunknown extends P ? Recordstring, any : P; data?: D; // ... }注意paramsSerializer的条件类型unknown extends P ? Recordstring, any : P当P被显式指定为具体类型时序列化器参数获得精确类型当P为默认的any时回退为Recordstring, any从而保证向后兼容。完整示例import axios, { type AxiosPromise, type AxiosRequestConfig, type InternalAxiosRequestConfig, } from axios; interface RequestBody { includeArchived: boolean; } interface SearchParams { query: string; page?: number; } interface SearchResponse { results: string[]; } const searchConfig: AxiosRequestConfigRequestBody, SearchParams { data: { includeArchived: false }, params: { query: axios, page: 1 }, paramsSerializer: (params) ${params.query}:${params.page ?? 1}, }; const response await axios.get(/search, searchConfig); response.config.data; // RequestBody | undefined response.config.params; // SearchParams | undefined const invalidConfig: AxiosRequestConfigRequestBody, SearchParams { // ts-expect-error query 必须是字符串 params: { query: 123 }, };这段代码演示了两个关键能力响应回传默认响应中response.config保留了D与PAxiosResponse的config字段类型即InternalAxiosRequestConfigD, P见 index.d.ts即使请求是通过带类型的配置推断出来的别名方法D、P依然被完整携带编译期拦截错误params的类型是SearchParams把query写成数字会在编译期被ts-expect-error捕获。除AxiosResponse与AxiosPromise外RawAxiosRequestConfig、InternalAxiosRequestConfig、AxiosDefaults、CreateAxiosDefaults、AxiosError、CanceledError、可调用实例、适配器等类型以及mergeConfig()函数index.d.tsmergeConfigD, P(config1, config2): AxiosRequestConfigD, P也都会保留P即参数类型不会在整条配置链路上丢失。请求方法新增的第四个泛型 P请求方法get/post/put等在原有三个泛型之后追加了P签名为T, R, D, Pindex.d.tsgetT any, R AxiosResponseDefault, D any, P any( url: string, config?: AxiosRequestConfigD, P ): PromiseAxiosResponseResultT, R, D, P;T响应数据类型R自定义响应类型默认哨兵值AxiosResponseDefault表示使用标准AxiosResponse见 index.d.ts 的AxiosResponseResult条件类型D请求数据P查询参数默认any以保持向后兼容。由于P追加在末尾既有代码中T、R、D的位置不变现有泛型写法无需迁移。显式提供的响应类型R仍然决定 Promise 的 resolve 值。显式带类型的适配器或任意 Promise同样可以保留两个请求类型const searchAdapter ( config: InternalAxiosRequestConfigRequestBody, SearchParams ): AxiosPromiseSearchResponse, RequestBody, SearchParams Promise.resolve({ data: { results: [] }, status: 200, statusText: OK, headers: {}, config, }); declare const error: unknown; if (axios.isCancelSearchResponse, RequestBody, SearchParams(error)) { error.config?.data; // RequestBody | undefined error.config?.params; // SearchParams | undefined }这里AxiosPromiseT, D, P被声明为PromiseAxiosResponseT, D, {}, Pindex.d.ts错误守卫isCancelT, D, P收窄后也能读取带类型的config.data/config.params形成「请求 → 响应 → 错误」三个方向一致的类型闭环。类型化的实例与拦截器用AxiosInstance标注axios.create的返回值并用InternalAxiosRequestConfig标注请求拦截器参数即可为自定义客户端获得端到端的类型检查import axios, { AxiosInstance, InternalAxiosRequestConfig } from axios; const apiClient: AxiosInstance axios.create({ baseURL: https://api.example.com, timeout: 10000, }); apiClient.interceptors.request.use((config: InternalAxiosRequestConfig) { // 添加认证 token、记录日志等 return config; });AxiosInstance的定义index.d.ts在Axios类之上追加了可调用签名apiClientUser(/users/1)与apiClientUser({ url: /users/1 })两种写法都有完整泛型推导create返回的仍是AxiosInstance其defaults属性带有headers索引签名。默认导出被声明为AxiosStaticindex.d.ts它继承AxiosInstance并暴露isCancel、isAxiosError、mergeConfig、toFormData、CanceledError、AxiosHeaders等工具因此axios.get、axios.interceptors与上述静态函数共享同一套类型。使用 Symbol 键扩展请求配置axios 在合并默认配置与单次请求配置时会保留自有且可枚举的 Symbol 属性。这一行为的实现证据在 lib/core/mergeConfig.jsif (Object.getOwnPropertySymbols Object.getOwnPropertyDescriptor) { return Object.keys(thing).concat( Object.getOwnPropertySymbols(thing).filter( (symbol) Object.getOwnPropertyDescriptor(thing, symbol).enumerable ) ); }即只有「自有own且可枚举enumerable」的 Symbol 属性会参与拷贝继承来的或非可枚举的 Symbol 属性不会被复制。利用这一点应用可以通过模块增强module augmentation给AxiosRequestConfig增加一个精确的 Symbol 键并在拦截器/适配器中通过InternalAxiosRequestConfig读取import axios from axios; export const someFlag: unique symbol Symbol( some flag used in request interceptor ); declare module axios { interface AxiosRequestConfigD any, P any { [someFlag]?: boolean; } } axios.interceptors.request.use((config) { if (config[someFlag]) { config.headers.set(X-Some-Flag, enabled); } return config; }); await axios.get(/users, { [someFlag]: true });这种方案的优势在于键名是unique symbol不会与公共配置字段冲突且declare module axios的增强会全局生效于项目内所有引用 axios 类型的文件。响应数据的泛型标注axios 的请求方法针对响应数据类型是泛型的。给axios.getT以及其他别名方法传入类型参数即可为response.data标注类型interface User { id: number; name: string; } const { data } await apiClient.getUser(/users/1); // data 的类型为 User配合前面介绍的D、P参数一个接口调用可以完整表达四种类别T响应、R自定义响应结构、D请求体、P查询参数例如apiClient.getUser, void, RequestBody, SearchParams(url, config)。参考与延伸阅读官方文档本文骨架docs/fr/pages/advanced/type-script.md英文版见 docs/pages/advanced/type-script.md类型声明入口index.d.tsESM、index.d.ctsCJS双格式发布配置package.json错误守卫实现lib/helpers/isAxiosError.jsSymbol 属性合并实现lib/core/mergeConfig.jsTypeScript 入门示例docs/pages/getting-started/examples/typescript.md类型兼容测试ESM/CJS 双格式下的 typings 校验tests/module/esm/tests/typings.module.test.js、tests/module/cjs/tests/typings.module.test.cjs适用前提本文的类型行为以当前仓库 package.json 中的axios1.19.0声明文件为准moduleResolution: node16要求 TypeScript 4.7 及以上版本低版本编译器请按前文表格选择esModuleInterop等替代配置。【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考