Skip to content

TypeScript ​

axios incluye definiciones de TypeScript en el paquete npm a través de index.d.ts (ESM) e index.d.cts (CJS), por lo que la verificación de tipos y el soporte del editor funcionan de manera nativa para ambos formatos de módulo.

Consideraciones sobre la resolución de módulos ​

Dado que axios publica de forma dual con una exportación por defecto ESM y un module.exports CJS, hay algunas consideraciones de configuración:

  • La configuración recomendada es "moduleResolution": "node16" (implícita en "module": "node16"). Esto requiere TypeScript 4.7 o superior.
  • Si usas ESM, tu configuración debería estar bien.
  • Si compilas TypeScript a CJS y no puedes usar "moduleResolution": "node16", debes habilitar esModuleInterop.
  • Si usas TypeScript para verificar tipos en código JavaScript CJS, tu única opción es "moduleResolution": "node16".

Type guards para errores de axios ​

Usa el type guard axios.isAxiosError para reducir de forma segura los errores unknown en bloques catch. Tras la reducción, puedes acceder a propiedades específicas de axios como error.response, error.config y error.code con seguridad de tipos completa.

ts
import axios from "axios";

let user: User | null = null;
try {
  const { data } = await axios.get("/user?ID=12345");
  user = data.userDetails;
} catch (error) {
  if (axios.isAxiosError(error)) {
    handleAxiosError(error);
  } else {
    handleUnexpectedError(error);
  }
}

Usa axios.isCancel<T>() para reducir los errores de cancelación a CanceledError<T>:

ts
const controller = new AbortController();

try {
  await axios.get<User>("/user?ID=12345", { signal: controller.signal });
} catch (error) {
  if (axios.isCancel<User>(error)) {
    handleCancellation(error);
  }
}

Tipado de los datos de solicitud y los parámetros de consulta ​

AxiosRequestConfig<D = any, P = any> usa D para los datos de la solicitud y P para los parámetros de consulta. Un serializador de parámetros personalizado recibe el mismo P:

ts
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: AxiosRequestConfig<RequestBody, 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: AxiosRequestConfig<RequestBody, SearchParams> = {
  // @ts-expect-error `query` debe ser una cadena
  params: { query: 123 },
};

Los resultados predeterminados conservan D y P en response.config, incluso cuando los alias de solicitud infieren esos tipos a partir de una configuración tipada. RawAxiosRequestConfig, InternalAxiosRequestConfig, AxiosDefaults, CreateAxiosDefaults, AxiosResponse, AxiosPromise, AxiosError, CanceledError, las instancias invocables, los adaptadores y mergeConfig() también conservan el tipo de los parámetros.

Los métodos de solicitud añaden P como último genérico —<T, R, D, P>— para mantener sin cambios las posiciones existentes de datos de respuesta (T), respuesta personalizada (R) y datos de solicitud (D). Un tipo de respuesta personalizado proporcionado explícitamente sigue controlando el valor resuelto. P vale any por defecto para mantener la compatibilidad.

Un adaptador u otra promesa tipada explícitamente puede conservar ambos tipos de la solicitud:

ts
const searchAdapter = (
  config: InternalAxiosRequestConfig<RequestBody, SearchParams>
): AxiosPromise<SearchResponse, RequestBody, SearchParams> =>
  Promise.resolve({
    data: { results: [] },
    status: 200,
    statusText: "OK",
    headers: {},
    config,
  });

declare const error: unknown;

if (axios.isCancel<SearchResponse, RequestBody, SearchParams>(error)) {
  error.config?.data;   // RequestBody | undefined
  error.config?.params; // SearchParams | undefined
}

Instancias e interceptores tipados ​

Anota el resultado de axios.create con AxiosInstance, y anota los interceptores de solicitud con InternalAxiosRequestConfig para obtener verificación de tipos de extremo a extremo en un cliente personalizado:

ts
import axios, { AxiosInstance, InternalAxiosRequestConfig } from "axios";

const apiClient: AxiosInstance = axios.create({
  baseURL: "https://api.example.com",
  timeout: 10000,
});

apiClient.interceptors.request.use((config: InternalAxiosRequestConfig) => {
  // Añadir token de autenticación, registrar, etc.
  return config;
});

Configuración de solicitud personalizada con claves de tipo símbolo ​

axios conserva las propiedades de símbolo propias y enumerables al combinar la configuración predeterminada con la de cada solicitud. Las aplicaciones pueden ampliar AxiosRequestConfig con una clave de símbolo específica y leer la opción desde InternalAxiosRequestConfig en un interceptor o adaptador:

ts
import axios from "axios";

export const someFlag: unique symbol = Symbol(
  "some flag used in request interceptor"
);

declare module "axios" {
  interface AxiosRequestConfig<D = 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 });

Solo se copian las propiedades de símbolo propias y enumerables. Las propiedades de símbolo heredadas o no enumerables no se copian.

Tipado de los datos de respuesta ​

Los métodos de solicitud de Axios son genéricos sobre el tipo de los datos de respuesta. Pasa un parámetro de tipo a axios.get<T> (y a los demás alias) para tipar response.data:

ts
interface User {
  id: number;
  name: string;
}

const { data } = await apiClient.get<User>("/users/1");
// `data` está tipado como `User`

axios is provided under MIT license