Daniel M
Daniel M

Reputation: 143

How to access Axios error response object in catch clause?

I recently upgraded to axios 0.23.0 and I am now receiving an error when trying to access the error response object in a catch clause. This is where I am getting the error:

  const loginUser = async (userData: UserPayload): Promise<void> => {
    try {
      const result = await login(userData);
      const { token } = result.data;
      localStorage.setItem('jwtTokenTS', token);
      setupAxios(token);
      const decoded: User = jwt_decode(token);
      setUser(decoded);
      setAuthenticated(true);
    } catch (err) {
      if (err.response.status === 404) {
        window.alert('User not found');
      } else if (err.response.status === 401) {
        window.alert('Incorrect password');
      } else {
        console.error(err);
      }
    }
  };

The "login" function on line 3 is my axios request as seen below:

export async function login(user: UserPayload): Promise<AxiosResponse<{ token: string }>> {
  return axios.post(`${bConfig.backend}/login`, user);
}

The exact error I receive is when trying to access "err.response.status":

Object is of type 'unknown'.ts(2571) (local var) err: unknown

Any ideas on how to get rid of this error will be appreciated, I have tried typing the error at the catch clause but typescript doesn't like this either.

Upvotes: 2

Views: 4167

Answers (2)

Michael Bo&#241;on
Michael Bo&#241;on

Reputation: 194

Update: As mentioned by @matas-ramanauskas in another answer, a built-in type guard available from Axios (see https://github.com/axios/axios/pull/3546/files). The built in type guard should be able to handle also when the object being checked is null since error.isAxiosError will return an error is error is null.

I've also updated the code below to check whether error is not null or not undefined before checking the isAxiosError property.


Since TypeScript 4.4, catch clause variables are now defaulted from any to unknown type unless configured not to. This allows for safer handling as it forces users to check the type of caught value in the catch clause before being used. To get rid of that error, you need to use a type guard to narrow down the possible types of the object to let TypeScript know what type it is dealing with.

You can do something like this:

const isAxiosError = (error: unknown): error is AxiosError => {
  return error && (error as AxiosError).isAxiosError;
};

try {
  // ...
} catch (err) {
  if (isAxiosError(err) && err.response) {
    if (err.response.status === 404) {
      window.alert('User not found');
    } else if (err.response.status === 401) {
      window.alert('Incorrect password');
    } else {
      console.error(err);
    }
  } else {
    console.error(err);
  }
}

You can check out the guide I made specifically for this scenarios. https://www.linkedin.com/posts/michael-bonon_handling-typed-errors-in-typescript-44-activity-6865161464236400640-MkWB

Upvotes: 5

Matas Ramanauskas
Matas Ramanauskas

Reputation: 31

Michael explains the reasoning and solution well. However his type guard function is not 100% correct and might cause problems (like (error as AxiosError).isAxiosError will give you error if you try to catch something like throw "abc";). I suggest using default axios type guard available since v0.21.1 December 21, 2020 (https://github.com/axios/axios/blob/master/CHANGELOG.md):

try {
  // ...
} catch (err) {
  if (axios.isAxiosError(err) && err.response) {
   ...
  }
}

Upvotes: 2

Related Questions