You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级Axios至1.7.7后TS报错:避免每次调用传Headers的方案

Axios升级到1.7.7后的TypeScript类型错误解决方案

问题描述

将Axios从0.28.0升级到1.7.7后,自定义Axios实例调用时必须重复传入headers字段,否则触发以下TypeScript错误:

TS2345: Argument of type '{ params: { accountType: string; }; }' is not assignable to parameter of type 'RequestConfig'.   Property 'headers' is missing in type '{ params: { accountType: string; }; }' but required in type 'InternalAxiosRequestConfig<any>'.

原因分析

Axios 1.x版本中,InternalAxiosRequestConfig是内部处理请求时的专用类型,其中headers被标记为必填字段;而外部调用接口时应使用的AxiosRequestConfig类型中,headers是可选的。你自定义的RequestConfig错误继承了InternalAxiosRequestConfig,导致外部调用必须满足内部类型的必填约束,引发报错。

解决方案

方案1:移除自定义类型,直接使用Axios原生类型

删除自定义的RequestConfig和CustomHttpInstance类型定义,直接使用Axios提供的AxiosInstance类型,自动适配外部调用的AxiosRequestConfig(headers为可选字段):

修改后的核心代码:

import axios, {
  AxiosInstance,
  InternalAxiosRequestConfig,
  AxiosResponse,
} from 'axios';
import CryptoJS from 'crypto-js';
import { appConfig } from '../config/env';

const customHttpProvider: AxiosInstance = axios.create({
  baseURL: appConfig.api.baseUrl,
  headers: {
    'X-SIGN-TYPE': 2,
    'X-API-KEY': appConfig.api.apiKey,
    'Content-Type': 'application/json',
  },
});

customHttpProvider.interceptors.request.use(async (config: InternalAxiosRequestConfig) => {
  const timestamp = Date.now().toString();
  const apiKey = appConfig.api.apiKey;
  const secretKey = appConfig.api.apiSecret;
  const recvWindow = 5000;
  let payload = '';

  if (config.params && Object.keys(config.params).length) {
    payload = Object.keys(config.params)
      .map(key => `${key}=${encodeURIComponent(config.params[key])}`)
      .join('&');
  }

  if (config.data) {
    payload = JSON.stringify(config.data);
  }

  const body = timestamp + apiKey + recvWindow + payload;
  const apiSignature = CryptoJS.algo.HMAC.create(
    CryptoJS.algo.SHA256,
    secretKey,
  )
    .update(body)
    .finalize()
    .toString(CryptoJS.enc.Hex);

  config.headers['X-SIGN'] = apiSignature;
  config.headers['X-TIMESTAMP'] = timestamp;
  config.headers['X-RECV-WINDOW'] = recvWindow;

  return config;
});

customHttpProvider.interceptors.response.use(
  (response) => response.data,
  (error) => Promise.reject(error.response?.data || error),
);

export default customHttpProvider;

调用示例(无需重复传headers):

const getBalance = (accountType: string = 'UNIFIED') => {
  return customHttpProvider.get<{
    retCode: number;
    retMsg: string;
    result: {
      memberId: string;
      accountType: string;
      balance: {
        coin: string;
        transferBalance: string;
        walletBalance: string;
        bonus: '';
      }[];
    };
    retExtInfo: Record<string, any>;
    time: number;
  }>('/v5/asset/transfer/query-account-coins-balance', {
    params: {
      accountType,
    },
  });
};

方案2:修正自定义RequestConfig类型,将headers设为可选

若需保留自定义类型结构,修改RequestConfig将headers改为可选字段:

import axios, {
  AxiosInstance,
  AxiosInterceptorManager,
  AxiosPromise,
  InternalAxiosRequestConfig,
  AxiosResponse,
} from 'axios';
import CryptoJS from 'crypto-js';
import { appConfig } from '../config/env';

// 将headers字段改为可选
interface RequestConfig extends Omit<InternalAxiosRequestConfig, 'headers'> {
  headers?: InternalAxiosRequestConfig['headers'];
}

interface CustomHttpInstance extends AxiosInstance {
  (config: RequestConfig): AxiosPromise;
  (url: string, config?: RequestConfig): AxiosPromise;
  interceptors: {
    request: AxiosInterceptorManager<RequestConfig>;
    response: AxiosInterceptorManager<AxiosResponse>;
  };
  getUri(config?: RequestConfig): string;
  request<T = any, R = T>(config: RequestConfig): Promise<R>;
  get<T = any, R = T>(url: string, config?: RequestConfig): Promise<R>;
  delete<T = any, R = T>(url: string, config?: RequestConfig): Promise<R>;
  head<T = any, R = T>(url: string, config?: RequestConfig): Promise<R>;
  options<T = any, R = T>(url: string, config?: RequestConfig): Promise<R>;
  post<T = any, R = T>(
    url: string,
    data?: any,
    config?: RequestConfig,
  ): Promise<R>;
  put<T = any, R = T>(
    url: string,
    data?: any,
    config?: RequestConfig,
  ): Promise<R>;
  patch<T = any, R = T>(
    url: string,
    data?: any,
    config?: RequestConfig,
  ): Promise<R>;
}

const customHttpProvider: CustomHttpInstance = axios.create({
  baseURL: appConfig.api.baseUrl,
  headers: {
    'X-SIGN-TYPE': 2,
    'X-API-KEY': appConfig.api.apiKey,
    'Content-Type': 'application/json',
  },
}) as CustomHttpInstance;

// 拦截器逻辑保持不变
customHttpProvider.interceptors.request.use(async (config: RequestConfig) => {
  // ... 原有代码
  return config;
});

customHttpProvider.interceptors.response.use(
  (response) => response.data,
  (error) => Promise.reject(error.response?.data || error),
);

export default customHttpProvider;

此方案既保留自定义类型,又允许调用时不强制传入headers。

内容的提问来源于stack exchange,提问作者rahulserver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 00:12:33