Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type of AxiosError gets narrowed down after isCancel check #5153

Open
maiolica opened this issue Oct 18, 2022 · 3 comments · May be fixed by #5595
Open

Type of AxiosError gets narrowed down after isCancel check #5153

maiolica opened this issue Oct 18, 2022 · 3 comments · May be fixed by #5595

Comments

@maiolica
Copy link

maiolica commented Oct 18, 2022

Describe the bug

After a isCancel check the type of the argument passed gets narrowed down, losing the AxiosError type.
The type is not narrowed down in version 0.27.2.

To Reproduce

https://typescript-l4zgey.stackblitz.io/

Code snippet

import axios, { AxiosError } from 'axios';

export const showError = (error?: AxiosError) => {
  // Type of `error` is `AxiosError<unknown, any> | undefined`
  if (axios.isCancel(error)) {
    return;
  }
  
  // Type of `error` is `undefined`, but should also still be `AxiosError<unknown, any>`
  console.log(error)
};

Expected behavior

Type AxiosError should not be excluded after a isCancel check.

Axios Version

1.1.3

Adapter Version

No response

Browser

No response

Browser Version

No response

Node.js Version

16.16.0

OS

OSX 12.6.0

Additional Library Versions

Visual Studio Code 1.72.2
TypeScript 4.8.4

Additional context/Screenshots

No response

@adimit
Copy link

adimit commented Mar 10, 2023

We ran into this, too.

Since #4293, isCancel has a type guard:

  isCancel(value: any): value is Cancel;

That's all well and good in the positive case, but in the negative case, this type guard asserts that value is not a Cancel. What's a Cancel in the current typing?

export interface Cancel {
  message: string | undefined;
}

So this implies that whatever value is, it doesn't have a message. And AxiosError does have a message. And so value can't be an AxiosError. Since there's nothing left for value to be, TS infers it's never.

The actual runtime of isCancel only checks if the argument has the __CANCEL__ property on its prototype.

I think the type guard for isCancel is wrong. When you look at the implementation, isCancel checks whether the object is a CanceledError. CanceledError is just a subclass of AxiosError with a special name (and the aforementioned __CANCEL__ reification). I have no idea what interface Cancel is supposed to be.

Curiously, there's a CanceledError already in the typings. Changing the typeguard on isCancel

  isCancel(value: any): value is CanceledError

should fix the problem, but it's a breaking change. I could test it & draft a PR.

Unfortunately, this doesn't seem to fix the problem. The type guard seems to still refute AxiosError on value after failing the type guard check for CanceledError, even though CanceledError is a subtype of AxiosError.

PS: Ah, I found out what Cancel is. I'm pretty sure it isn't anything anymore, and that typing is purely a mistake. Commit 7f12366 did away with Cancel, but I guess the typings are just out of date.

@adimit
Copy link

adimit commented Mar 10, 2023

OK, I found out why my fix didn't work. I've opened up a bug in TS, and I know of a workaround. I'll post a PR.

Edit: it's not a bug in TS. TS considers this working as intended.

@adimit adimit linked a pull request Mar 10, 2023 that will close this issue
InteractiveNinja added a commit to InteractiveNinja/raycast-linkding-ext that referenced this issue Nov 7, 2023
@Pomar81
Copy link

Pomar81 commented Nov 16, 2023

workaround in project

declare module 'axios' { interface Cancel { readonly __CANCEL__: true } }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants