axios 返回值类型能不能改

新手上路,请多包涵

我这边response拦截器返回的是response.data

import Axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
import config from '@/utils/config'
import { message } from 'ant-design-vue';

const request = Axios.create({
  baseURL: config.baseUrl,
  timeout: 5000,
  headers: {
    Authorization: ''
  }
})

// 请求拦截器
request.interceptors.request.use((config: AxiosRequestConfig) => {
  return config
}, (err) => {
  message.error(err.toString())
  return Promise.reject(err)
})

// 请求拦截器
request.interceptors.response.use((response: AxiosResponse<{ code: number, data: string }>) => {
  if (response.status !== 200) {
    message.error('请求出错')
  }
  return Promise.resolve(response.data)
}, (err: any) => {
  message.error(err.toString())
  return Promise.reject(err.toString())
})

export default request

为什么在别的地方调用的时候报错呢
image.png

阅读 6.8k
4 个回答

改一下 axios 的类型声明即可,src 下添加 axios.d.ts(名字随你喜欢):

import { AxiosRequestConfig } from 'axios'

declare module 'axios' {
  // 这个是拓展 axios 的 config 类型的,不用在意
  export interface AxiosRequestConfig {
    validityTime?: number,
    disableCache?: boolean
  }

  export interface AxiosInstance {
    <T = any>(config: AxiosRequestConfig): Promise<T>,
    request<T = any>(config: AxiosRequestConfig): Promise<T>,
    get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>,
    delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>,
    head<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>,
    post<T = any>(
      url: string,
      data?: any,
      config?: AxiosRequestConfig
    ): Promise<T>,
    put<T = any>(
      url: string,
      data?: any,
      config?: AxiosRequestConfig
    ): Promise<T>,
    patch<T = any>(
      url: string,
      data?: any,
      config?: AxiosRequestConfig
    ): Promise<T>
  }
}

这样子可以使得 axios 上的方法能够根据泛型来控制返回类型:

interface Result<T = string> {
  code: number,
  data: T
}

axios.get<Result>('/url') // 返回 Primise<Result<string>>

当然你可以直接把默认类型定义在 .d.ts 文件里,只要把里面的 <T = any>any 改成你想要的默认类型即可。

比如把 Get 的改成这样后:

interface Result<T = string> {
  code: number,
  data: T
}

interface AxiosInstance {
  get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>
}

image.png

接口返回的字段,前端是不能改的。
你截图那个问题,要不你先看看res有什么内容?

返回值是在data上的,res上没有code

request.get<{ code: string }>('').then((res) => {
  res.data.code;
});

提供一个封装思路,预定义接口类型,这样写的时候都会有完整类型提示,不必一直查文档

import axios from "axios";

import type {
  Method,
  AxiosResponse,
  AxiosInstance,
  AxiosRequestConfig,
} from "axios";

/** 类型定义 */
type UnionToIntersection<Union> = (
  Union extends unknown ? (distributedUnion: Union) => void : never
) extends (mergedIntersection: infer Intersection) => void
  ? Intersection
  : never;

type Route = {
  method: Method;
  req: any;
  resp: any;
};

type APIModel = {
  [key in string]: Route | APIModel;
};

type Routes<
  T extends APIModel,
  Prefix extends string = "",
  Key = keyof T
> = Key extends string
  ? T[Key] extends APIModel
    ? Routes<T[Key], `${Prefix}${Key}`>
    : {
        [key in `${Prefix}${Key}`]: T[Key];
      }
  : never;

type GetRoutes<T extends APIModel> = UnionToIntersection<
  Routes<T>
> extends Record<string, Route>
  ? UnionToIntersection<Routes<T>>
  : never;

interface InitParams {
  config?: AxiosRequestConfig;
  callback?: (instance: AxiosInstance) => void;
}

type AxiosOptions = Omit<
  AxiosRequestConfig,
  "method" | "url" | "params" | "data"
>;

type Params<T extends Record<string, Route>, K extends keyof T> = NonNullable<
  T[K]["req"]
> extends never
  ? [K extends string ? K : string, T[K]["method"], null?, AxiosOptions?]
  : [K extends string ? K : string, T[K]["method"], T[K]["req"], AxiosOptions?];

interface Request<API extends APIModel> {
  <T extends keyof GetRoutes<API>>(
    ...items: Params<GetRoutes<API>, T>
  ): Promise<GetRoutes<API>[T]["resp"]>;
}
/**---------------- */

function isGet(method: Method): method is "get" | "GET" {
  return ["get", "GET"].includes(method);
}

function initRequest<T extends APIModel = APIModel>({
  config,
  callback,
}: InitParams = {}) {
  const instance = axios.create(config);
  callback?.(instance);

  const request: Request<T> = async (...items) => {
    const [url, method, data, config = {}] = items;
    const base: AxiosRequestConfig = {
      url,
      method,
      ...config,
    };

    if (data) {
      base[isGet(method) ? "params" : "data"] = data;
    }

    const res = await instance(base);

    return res["data"];
  };

  return {
    instance,
    request,
  };
}

开始测试

/** 测试代码 */
type Demo = {
  "/login": {
    method: "GET";
    req: {
      a: string;
    };
    resp: string[];
  };
  "/demo": {
    "/login": {
      method: "POST";
      req: undefined;
      resp: {
        code: string;
        number: number;
      };
    };
    "/te": {
      method: "POST";
      req: string[];
      resp: {
        msg: string;
      };
    };
  };
};
const { instance, request } = initRequest<Demo>({
  config: {
    baseURL: "",
    timeout: 5000,
    headers: {
      Authorization: "",
    },
  },
  callback(instance) {
    // 请求拦截器
    instance.interceptors.request.use(
      (config: AxiosRequestConfig) => {
        return config;
      },
      (err) => {
        // message.error(err.toString());
        return Promise.reject(err);
      }
    );

    // 请求拦截器
    instance.interceptors.response.use(
      (response: AxiosResponse<{ code: number; data: string }>) => {
        if (response.status !== 200) {
          // message.error("请求出错");
        }
        return Promise.resolve(response.data);
      },
      (err: any) => {
        // message.error(err.toString());
        return Promise.reject(err.toString());
      }
    );
  },
});

request("/login", "GET", { a: "" }).then((data) => {});
request("/demo/login", "POST").then((data) => {});
request("/demo/login", "POST", null, {
  headers: {},
}).then((data) => {});
request("/demo/te", "POST", []).then((data) => {});

export { instance, request };
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Microsoft
子站问答
访问
宣传栏