axios-mock-adapter
axios-mock-adapter copied to clipboard
TypeScript error when axios instance is created from an import that uses `axios >=1.6.0`'s ESM types
Overview
With [email protected], [email protected], [email protected], using MockAdapter causes TypeScript to error about type differences between axios when imported via our ESM code and the types imported by axios-mock-adapter.
The newest axios version that this does not occur is [email protected], the type change seems to be introduced in [email protected]. However, I don't believe it's an axios issue, or at least one that's as straightforward as you may expect. axios's types ESM and CJS are composed of the same literals and unions for AxiosRequestHeaders, so I feel like TypeScript is providing an unhelpful error about assignability of members of what is functionally the same union. The crux is that the classes AxiosHeaders (ESM) and axios.AxiosHeaders (CJS) are not assignable.
Besides downgrading to [email protected], this also doesn't occur when using .cts or "type": "script". Unfortunately downgrading to a vulnerable axios version and rewriting our modules to CommonJS are not feasible workarounds for my team, so we're as any'ing the errors away.
Possible Fix
It appears that axios-retry fixed this assignability issue occurring from the different type files by using ESM or CJS axios types based on whether axios-retry was imported from ESM or CJS: https://github.com/softonic/axios-retry/issues/159#issuecomment-1809406232. Perhaps this approach would work for axios-mock-adapter?
CodeSandbox
https://codesandbox.io/p/devbox/yxnj2p?file=%2Fsrc%2Findex.ts%3A6%2C1
Error
Argument of type 'import("/project/workspace/node_modules/axios/index", { with: { "resolution-mode": "import" } }).AxiosInstance' is not assignable to parameter of type 'import("/project/workspace/node_modules/axios/index").AxiosInstance'.
Types of property 'defaults' are incompatible.
Type 'Omit<import("/project/workspace/node_modules/axios/index", { with: { "resolution-mode": "import" } }).AxiosDefaults<any>, "headers"> & { headers: import("/project/workspace/node_modules/axios/index", { with: { "resolution-mode": "import" } }).HeadersDefaults & { ...; }; }' is not assignable to type 'Omit<import("/project/workspace/node_modules/axios/index").AxiosDefaults<any>, "headers"> & { headers: import("/project/workspace/node_modules/axios/index").HeadersDefaults & { ...; }; }' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Type 'Omit<AxiosDefaults<any>, "headers"> & { headers: HeadersDefaults & { [key: string]: AxiosHeaderValue; }; }' is not assignable to type 'Omit<AxiosDefaults<any>, "headers">' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'transformRequest' are incompatible.
Type 'import("/project/workspace/node_modules/axios/index", { with: { "resolution-mode": "import" } }).AxiosRequestTransformer | import("/project/workspace/node_modules/axios/index", { with: { "resolution-mode": "import" } }).AxiosRequestTransformer[]' is not assignable to type 'import("/project/workspace/node_modules/axios/index").AxiosRequestTransformer | import("/project/workspace/node_modules/axios/index").AxiosRequestTransformer[]'.
Type 'AxiosRequestTransformer' is not assignable to type 'AxiosRequestTransformer | AxiosRequestTransformer[]'.
Type 'import("/project/workspace/node_modules/axios/index", { with: { "resolution-mode": "import" } }).AxiosRequestTransformer' is not assignable to type 'import("/project/workspace/node_modules/axios/index").AxiosRequestTransformer'.
The 'this' types of each signature are incompatible.
Type 'import("/project/workspace/node_modules/axios/index").InternalAxiosRequestConfig<any>' is not assignable to type 'import("/project/workspace/node_modules/axios/index", { with: { "resolution-mode": "import" } }).InternalAxiosRequestConfig<any>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'headers' are incompatible.
Type 'import("/project/workspace/node_modules/axios/index").AxiosRequestHeaders' is not assignable to type 'import("/project/workspace/node_modules/axios/index", { with: { "resolution-mode": "import" } }).AxiosRequestHeaders' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Type 'AxiosRequestHeaders' is not assignable to type 'Partial<RawAxiosHeaders & { Accept: AxiosHeaderValue; "Content-Length": AxiosHeaderValue; "User-Agent": AxiosHeaderValue; "Content-Encoding": AxiosHeaderValue; Authorization: AxiosHeaderValue; } & { ...; }>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'Accept' are incompatible.
Type 'import("/project/workspace/node_modules/axios/index").AxiosHeaderValue' is not assignable to type 'import("/project/workspace/node_modules/axios/index", { with: { "resolution-mode": "import" } }).AxiosHeaderValue'.
Type 'AxiosHeaders' is not assignable to type 'AxiosHeaderValue'.
Type 'AxiosHeaders' is missing the following properties from type 'string[]': length, pop, push, join, and 33 more.
Minimal TypeScript Code Triggering Error
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
export const axiosInstance = axios.create({});
new MockAdapter(axiosInstance);
TypeScript Config
{
"compilerOptions": {
"lib": [
"esnext",
"dom"
],
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"strict": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true
}
}
@remcohaszing I saw you were an author on axios's ESM types and you fixed #371. You seem knowledgeable about this area, and I hope you don't mind the ping. ❤️
I think https://github.com/axios/axios/pull/6218 would resolve the issue.
Any chance there is some sort of workaround to make this work until this is merged in?
Any chance there is some sort of workaround to make this work until this is merged in?
@yourinium as @evelynhathaway said a dirty "any" cast will keep it compiling until we have a proper fix, e.g.
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
axiosMock = new MockAdapter(axios as any);
It's worth noting that the aforementioned https://github.com/axios/axios/pull/6218 was merged, but reverted in 1.7.9 due to making a breaking change that broke Typescript compilation upstream for a lot of users (https://github.com/axios/axios/issues/6720). So it'll be longer still before we see this fixed upstream.
Since axios-mock-adapter does not currently support [email protected], I added a simple compatibility layer to make it work for now:
// axios-mock-adapter-compat.ts
import type { AxiosInstance } from 'axios';
import AxiosMockAdapter from 'axios-mock-adapter';
interface MockAdapterOptions {
delayResponse?: number;
onNoMatch?: 'passthrough' | 'throwException';
}
/**
* Temporary compatibility layer for axios-mock-adapter.
* Allows it to work with [email protected] by casting the instance type.
* @see https://github.com/ctimmerm/axios-mock-adapter/issues/400
*/
export default class MockAdapter extends AxiosMockAdapter {
constructor(axiosInstance: AxiosInstance, options?: MockAdapterOptions) {
// eslint-disable-next-line
super(axiosInstance as any, options);
}
}
Then updated imports:
// Previous
import MockAdapter from 'axios-mock-adapter';
// New
import MockAdapter from './path/to/axios-mock-adapter-compat';
The issue is because TypeScript resolves either index.d.ts and index.d.cts depending on who imports it. This is why people should stop exporting dual-module packages.
I fixed it by pointing ts to a single file in my tsconfig.json
"paths": {
"axios": ["./node_modules/axios/index.d.ts"]
}
Also alternative solution: use declare module "axios" and copy-paste the entirety of axios' types into a globals.d.ts:
globals.d.ts
declare module "axios" {
// TypeScript Version: 4.7
export type AxiosHeaderValue =
| AxiosHeaders
| string
| string[]
| number
| boolean
| null;
interface RawAxiosHeaders {
[key: string]: AxiosHeaderValue;
}
type MethodsHeaders = Partial<
{
[Key in Method as Lowercase<Key>]: AxiosHeaders;
} & { common: AxiosHeaders }
>;
type AxiosHeaderMatcher =
| string
| RegExp
| ((this: AxiosHeaders, value: string, name: string) => boolean);
type AxiosHeaderParser = (
this: AxiosHeaders,
value: AxiosHeaderValue,
header: string,
) => any;
export class AxiosHeaders {
constructor(headers?: RawAxiosHeaders | AxiosHeaders | string);
[key: string]: any;
set(
headerName?: string,
value?: AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher,
): AxiosHeaders;
set(
headers?: RawAxiosHeaders | AxiosHeaders | string,
rewrite?: boolean,
): AxiosHeaders;
get(headerName: string, parser: RegExp): RegExpExecArray | null;
get(
headerName: string,
matcher?: true | AxiosHeaderParser,
): AxiosHeaderValue;
has(header: string, matcher?: AxiosHeaderMatcher): boolean;
delete(header: string | string[], matcher?: AxiosHeaderMatcher): boolean;
clear(matcher?: AxiosHeaderMatcher): boolean;
normalize(format: boolean): AxiosHeaders;
concat(
...targets: Array<
AxiosHeaders | RawAxiosHeaders | string | undefined | null
>
): AxiosHeaders;
toJSON(asStrings?: boolean): RawAxiosHeaders;
static from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders;
static accessor(header: string | string[]): AxiosHeaders;
static concat(
...targets: Array<
AxiosHeaders | RawAxiosHeaders | string | undefined | null
>
): AxiosHeaders;
setContentType(
value: ContentType,
rewrite?: boolean | AxiosHeaderMatcher,
): AxiosHeaders;
getContentType(parser?: RegExp): RegExpExecArray | null;
getContentType(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasContentType(matcher?: AxiosHeaderMatcher): boolean;
setContentLength(
value: AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher,
): AxiosHeaders;
getContentLength(parser?: RegExp): RegExpExecArray | null;
getContentLength(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasContentLength(matcher?: AxiosHeaderMatcher): boolean;
setAccept(
value: AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher,
): AxiosHeaders;
getAccept(parser?: RegExp): RegExpExecArray | null;
getAccept(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasAccept(matcher?: AxiosHeaderMatcher): boolean;
setUserAgent(
value: AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher,
): AxiosHeaders;
getUserAgent(parser?: RegExp): RegExpExecArray | null;
getUserAgent(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasUserAgent(matcher?: AxiosHeaderMatcher): boolean;
setContentEncoding(
value: AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher,
): AxiosHeaders;
getContentEncoding(parser?: RegExp): RegExpExecArray | null;
getContentEncoding(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasContentEncoding(matcher?: AxiosHeaderMatcher): boolean;
setAuthorization(
value: AxiosHeaderValue,
rewrite?: boolean | AxiosHeaderMatcher,
): AxiosHeaders;
getAuthorization(parser?: RegExp): RegExpExecArray | null;
getAuthorization(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
hasAuthorization(matcher?: AxiosHeaderMatcher): boolean;
[Symbol.iterator](): IterableIterator<[string, AxiosHeaderValue]>;
}
type CommonRequestHeadersList =
| "Accept"
| "Content-Length"
| "User-Agent"
| "Content-Encoding"
| "Authorization";
type ContentType =
| AxiosHeaderValue
| "text/html"
| "text/plain"
| "multipart/form-data"
| "application/json"
| "application/x-www-form-urlencoded"
| "application/octet-stream";
export type RawAxiosRequestHeaders = Partial<
RawAxiosHeaders & {
[Key in CommonRequestHeadersList]: AxiosHeaderValue;
} & {
"Content-Type": ContentType;
}
>;
export type AxiosRequestHeaders = RawAxiosRequestHeaders & AxiosHeaders;
type CommonResponseHeadersList =
| "Server"
| "Content-Type"
| "Content-Length"
| "Cache-Control"
| "Content-Encoding";
type RawCommonResponseHeaders = {
[Key in CommonResponseHeadersList]: AxiosHeaderValue;
} & {
"set-cookie": string[];
};
export type RawAxiosResponseHeaders = Partial<
RawAxiosHeaders & RawCommonResponseHeaders
>;
export type AxiosResponseHeaders = RawAxiosResponseHeaders & AxiosHeaders;
export interface AxiosRequestTransformer {
(
this: InternalAxiosRequestConfig,
data: any,
headers: AxiosRequestHeaders,
): any;
}
export interface AxiosResponseTransformer {
(
this: InternalAxiosRequestConfig,
data: any,
headers: AxiosResponseHeaders,
status?: number,
): any;
}
export interface AxiosAdapter {
(config: InternalAxiosRequestConfig): AxiosPromise;
}
export interface AxiosBasicCredentials {
username: string;
password: string;
}
export interface AxiosProxyConfig {
host: string;
port: number;
auth?: AxiosBasicCredentials;
protocol?: string;
}
export enum HttpStatusCode {
Continue = 100,
SwitchingProtocols = 101,
Processing = 102,
EarlyHints = 103,
Ok = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
MultiStatus = 207,
AlreadyReported = 208,
ImUsed = 226,
MultipleChoices = 300,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
UseProxy = 305,
Unused = 306,
TemporaryRedirect = 307,
PermanentRedirect = 308,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
PayloadTooLarge = 413,
UriTooLong = 414,
UnsupportedMediaType = 415,
RangeNotSatisfiable = 416,
ExpectationFailed = 417,
ImATeapot = 418,
MisdirectedRequest = 421,
UnprocessableEntity = 422,
Locked = 423,
FailedDependency = 424,
TooEarly = 425,
UpgradeRequired = 426,
PreconditionRequired = 428,
TooManyRequests = 429,
RequestHeaderFieldsTooLarge = 431,
UnavailableForLegalReasons = 451,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,
VariantAlsoNegotiates = 506,
InsufficientStorage = 507,
LoopDetected = 508,
NotExtended = 510,
NetworkAuthenticationRequired = 511,
}
export type Method =
| "get"
| "GET"
| "delete"
| "DELETE"
| "head"
| "HEAD"
| "options"
| "OPTIONS"
| "post"
| "POST"
| "put"
| "PUT"
| "patch"
| "PATCH"
| "purge"
| "PURGE"
| "link"
| "LINK"
| "unlink"
| "UNLINK";
export type ResponseType =
| "arraybuffer"
| "blob"
| "document"
| "json"
| "text"
| "stream"
| "formdata";
export type responseEncoding =
| "ascii"
| "ASCII"
| "ansi"
| "ANSI"
| "binary"
| "BINARY"
| "base64"
| "BASE64"
| "base64url"
| "BASE64URL"
| "hex"
| "HEX"
| "latin1"
| "LATIN1"
| "ucs-2"
| "UCS-2"
| "ucs2"
| "UCS2"
| "utf-8"
| "UTF-8"
| "utf8"
| "UTF8"
| "utf16le"
| "UTF16LE";
export interface TransitionalOptions {
silentJSONParsing?: boolean;
forcedJSONParsing?: boolean;
clarifyTimeoutError?: boolean;
}
export interface GenericAbortSignal {
readonly aborted: boolean;
onabort?: ((...args: any) => any) | null;
addEventListener?: (...args: any) => any;
removeEventListener?: (...args: any) => any;
}
export interface FormDataVisitorHelpers {
defaultVisitor: SerializerVisitor;
convertValue: (value: any) => any;
isVisitable: (value: any) => boolean;
}
export interface SerializerVisitor {
(
this: GenericFormData,
value: any,
key: string | number,
path: null | Array<string | number>,
helpers: FormDataVisitorHelpers,
): boolean;
}
export interface SerializerOptions {
visitor?: SerializerVisitor;
dots?: boolean;
metaTokens?: boolean;
indexes?: boolean | null;
}
// tslint:disable-next-line
export interface FormSerializerOptions extends SerializerOptions {}
export interface ParamEncoder {
(value: any, defaultEncoder: (value: any) => any): any;
}
export interface CustomParamsSerializer {
(params: Record<string, any>, options?: ParamsSerializerOptions): string;
}
export interface ParamsSerializerOptions extends SerializerOptions {
encode?: ParamEncoder;
serialize?: CustomParamsSerializer;
}
type MaxUploadRate = number;
type MaxDownloadRate = number;
type BrowserProgressEvent = any;
export interface AxiosProgressEvent {
loaded: number;
total?: number;
progress?: number;
bytes: number;
rate?: number;
estimated?: number;
upload?: boolean;
download?: boolean;
event?: BrowserProgressEvent;
lengthComputable: boolean;
}
type Milliseconds = number;
type AxiosAdapterName = "fetch" | "xhr" | "http" | string;
type AxiosAdapterConfig = AxiosAdapter | AxiosAdapterName;
export type AddressFamily = 4 | 6 | undefined;
export interface LookupAddressEntry {
address: string;
family?: AddressFamily;
}
export type LookupAddress = string | LookupAddressEntry;
export interface AxiosRequestConfig<D = any> {
url?: string;
method?: Method | string;
baseURL?: string;
allowAbsoluteUrls?: boolean;
transformRequest?: AxiosRequestTransformer | AxiosRequestTransformer[];
transformResponse?: AxiosResponseTransformer | AxiosResponseTransformer[];
headers?: (RawAxiosRequestHeaders & MethodsHeaders) | AxiosHeaders;
params?: any;
paramsSerializer?: ParamsSerializerOptions | CustomParamsSerializer;
data?: D;
timeout?: Milliseconds;
timeoutErrorMessage?: string;
withCredentials?: boolean;
adapter?: AxiosAdapterConfig | AxiosAdapterConfig[];
auth?: AxiosBasicCredentials;
responseType?: ResponseType;
responseEncoding?: responseEncoding | string;
xsrfCookieName?: string;
xsrfHeaderName?: string;
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void;
maxContentLength?: number;
validateStatus?: ((status: number) => boolean) | null;
maxBodyLength?: number;
maxRedirects?: number;
maxRate?: number | [MaxUploadRate, MaxDownloadRate];
beforeRedirect?: (
options: Record<string, any>,
responseDetails: {
headers: Record<string, string>;
statusCode: HttpStatusCode;
},
) => void;
socketPath?: string | null;
transport?: any;
httpAgent?: any;
httpsAgent?: any;
proxy?: AxiosProxyConfig | false;
cancelToken?: CancelToken;
decompress?: boolean;
transitional?: TransitionalOptions;
signal?: GenericAbortSignal;
insecureHTTPParser?: boolean;
env?: {
FormData?: new (...args: any[]) => object;
};
formSerializer?: FormSerializerOptions;
family?: AddressFamily;
lookup?:
| ((
hostname: string,
options: object,
cb: (
err: Error | null,
address: LookupAddress | LookupAddress[],
family?: AddressFamily,
) => void,
) => void)
| ((
hostname: string,
options: object,
) => Promise<
| [
address: LookupAddressEntry | LookupAddressEntry[],
family?: AddressFamily,
]
| LookupAddress
>);
withXSRFToken?:
| boolean
| ((config: InternalAxiosRequestConfig) => boolean | undefined);
fetchOptions?: Record<string, any>;
}
// Alias
export type RawAxiosRequestConfig<D = any> = AxiosRequestConfig<D>;
export interface InternalAxiosRequestConfig<D = any>
extends AxiosRequestConfig<D> {
headers: AxiosRequestHeaders;
}
export interface HeadersDefaults {
common: RawAxiosRequestHeaders;
delete: RawAxiosRequestHeaders;
get: RawAxiosRequestHeaders;
head: RawAxiosRequestHeaders;
post: RawAxiosRequestHeaders;
put: RawAxiosRequestHeaders;
patch: RawAxiosRequestHeaders;
options?: RawAxiosRequestHeaders;
purge?: RawAxiosRequestHeaders;
link?: RawAxiosRequestHeaders;
unlink?: RawAxiosRequestHeaders;
}
export interface AxiosDefaults<D = any>
extends Omit<AxiosRequestConfig<D>, "headers"> {
headers: HeadersDefaults;
}
export interface CreateAxiosDefaults<D = any>
extends Omit<AxiosRequestConfig<D>, "headers"> {
headers?: RawAxiosRequestHeaders | AxiosHeaders | Partial<HeadersDefaults>;
}
export interface AxiosResponse<T = any, D = any> {
data: T;
status: number;
statusText: string;
headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
config: InternalAxiosRequestConfig<D>;
request?: any;
}
export class AxiosError<T = unknown, D = any> extends Error {
constructor(
message?: string,
code?: string,
config?: InternalAxiosRequestConfig<D>,
request?: any,
response?: AxiosResponse<T, D>,
);
config?: InternalAxiosRequestConfig<D>;
code?: string;
request?: any;
response?: AxiosResponse<T, D>;
isAxiosError: boolean;
status?: number;
toJSON: () => object;
cause?: Error;
static from<T = unknown, D = any>(
error: Error | unknown,
code?: string,
config?: InternalAxiosRequestConfig<D>,
request?: any,
response?: AxiosResponse<T, D>,
customProps?: object,
): AxiosError<T, D>;
static readonly ERR_FR_TOO_MANY_REDIRECTS = "ERR_FR_TOO_MANY_REDIRECTS";
static readonly ERR_BAD_OPTION_VALUE = "ERR_BAD_OPTION_VALUE";
static readonly ERR_BAD_OPTION = "ERR_BAD_OPTION";
static readonly ERR_NETWORK = "ERR_NETWORK";
static readonly ERR_DEPRECATED = "ERR_DEPRECATED";
static readonly ERR_BAD_RESPONSE = "ERR_BAD_RESPONSE";
static readonly ERR_BAD_REQUEST = "ERR_BAD_REQUEST";
static readonly ERR_NOT_SUPPORT = "ERR_NOT_SUPPORT";
static readonly ERR_INVALID_URL = "ERR_INVALID_URL";
static readonly ERR_CANCELED = "ERR_CANCELED";
static readonly ECONNABORTED = "ECONNABORTED";
static readonly ETIMEDOUT = "ETIMEDOUT";
}
export class CanceledError<T> extends AxiosError<T> {}
export type AxiosPromise<T = any> = Promise<AxiosResponse<T>>;
export interface CancelStatic {
new (message?: string): Cancel;
}
export interface Cancel {
message: string | undefined;
}
export interface Canceler {
(message?: string, config?: AxiosRequestConfig, request?: any): void;
}
export interface CancelTokenStatic {
new (executor: (cancel: Canceler) => void): CancelToken;
source(): CancelTokenSource;
}
export interface CancelToken {
promise: Promise<Cancel>;
reason?: Cancel;
throwIfRequested(): void;
}
export interface CancelTokenSource {
token: CancelToken;
cancel: Canceler;
}
export interface AxiosInterceptorOptions {
synchronous?: boolean;
runWhen?: (config: InternalAxiosRequestConfig) => boolean;
}
type AxiosRequestInterceptorUse<T> = (
onFulfilled?: ((value: T) => T | Promise<T>) | null,
onRejected?: ((error: any) => any) | null,
options?: AxiosInterceptorOptions,
) => number;
type AxiosResponseInterceptorUse<T> = (
onFulfilled?: ((value: T) => T | Promise<T>) | null,
onRejected?: ((error: any) => any) | null,
) => number;
export interface AxiosInterceptorManager<V> {
use: V extends AxiosResponse
? AxiosResponseInterceptorUse<V>
: AxiosRequestInterceptorUse<V>;
eject(id: number): void;
clear(): void;
}
export class Axios {
constructor(config?: AxiosRequestConfig);
defaults: AxiosDefaults;
interceptors: {
request: AxiosInterceptorManager<InternalAxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
getUri(config?: AxiosRequestConfig): string;
request<T = any, R = AxiosResponse<T>, D = any>(
config: AxiosRequestConfig<D>,
): Promise<R>;
get<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>,
): Promise<R>;
delete<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>,
): Promise<R>;
head<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>,
): Promise<R>;
options<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>,
): Promise<R>;
post<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Promise<R>;
put<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Promise<R>;
patch<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Promise<R>;
postForm<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Promise<R>;
putForm<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Promise<R>;
patchForm<T = any, R = AxiosResponse<T>, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Promise<R>;
}
export interface AxiosInstance extends Axios {
<T = any, R = AxiosResponse<T>, D = any>(
config: AxiosRequestConfig<D>,
): Promise<R>;
<T = any, R = AxiosResponse<T>, D = any>(
url: string,
config?: AxiosRequestConfig<D>,
): Promise<R>;
defaults: Omit<AxiosDefaults, "headers"> & {
headers: HeadersDefaults & {
[key: string]: AxiosHeaderValue;
};
};
}
export interface GenericFormData {
append(name: string, value: any, options?: any): any;
}
export interface GenericHTMLFormElement {
name: string;
method: string;
submit(): void;
}
export function getAdapter(
adapters: AxiosAdapterConfig | AxiosAdapterConfig[] | undefined,
): AxiosAdapter;
export function toFormData(
sourceObj: object,
targetFormData?: GenericFormData,
options?: FormSerializerOptions,
): GenericFormData;
export function formToJSON(
form: GenericFormData | GenericHTMLFormElement,
): object;
export function isAxiosError<T = any, D = any>(
payload: any,
): payload is AxiosError<T, D>;
export function spread<T, R>(
callback: (...args: T[]) => R,
): (array: T[]) => R;
export function isCancel(value: any): value is Cancel;
export function all<T>(values: Array<T | Promise<T>>): Promise<T[]>;
export function mergeConfig<D = any>(
config1: AxiosRequestConfig<D>,
config2: AxiosRequestConfig<D>,
): AxiosRequestConfig<D>;
export interface AxiosStatic extends AxiosInstance {
create(config?: CreateAxiosDefaults): AxiosInstance;
Cancel: CancelStatic;
CancelToken: CancelTokenStatic;
Axios: typeof Axios;
AxiosError: typeof AxiosError;
HttpStatusCode: typeof HttpStatusCode;
readonly VERSION: string;
isCancel: typeof isCancel;
all: typeof all;
spread: typeof spread;
isAxiosError: typeof isAxiosError;
toFormData: typeof toFormData;
formToJSON: typeof formToJSON;
getAdapter: typeof getAdapter;
CanceledError: typeof CanceledError;
AxiosHeaders: typeof AxiosHeaders;
mergeConfig: typeof mergeConfig;
}
declare const axios: AxiosStatic;
export default axios;
}
The issue is because TypeScript resolves either
index.d.tsandindex.d.ctsdepending on who imports it. This is why people should stop exporting dual-module packages.I fixed it by pointing ts to a single file in my tsconfig.json
"paths": { "axios": ["./node_modules/axios/index.d.ts"] }Also alternative solution: use
declare module "axios"and copy-paste the entirety of axios' types into a globals.d.ts:globals.d.ts
It works great. Thanks! :)