TypeScript

Typescript에서 Error 처리하기

citron031 2023. 6. 22. 23:19

자바스크립트는 Error 객체를 통해서 에러를 발생시킬 수 있다.

throw new Error("Error !!!");
// or
throw Error("에러 !!!");

➡️ new 키워드 없이 Error 객체를 호출해도, new 키워드를 사용한 것과 동일한 결과가 나타난다.

 

자바스크립트에서 발생한 에러는 try catch문을 통해서 에러를 탐지하고, 핸들링할 수 있다.

function errorTest() {
  throw new Error("에러입니다. 🍌");
}

try {
  errorTest();
  console.log("성공!"); // 미출력
} catch(error) {
  console.log(error, "발생!"); // 출력
} finally {
  console.log("성공/실패 상관없이 반드시 실행."); // 출력
}

위의 코드에서 throw를 통해서 던져진 에러는 catch를 통해 error 인자로 전달되어 콘솔에 출력되게 된다.

 

다만, 위에 코드는 타입스크립트에서 처리할 때, 약간 문제점이 발생한다.

error인자의 타입이 무조건 any(typescript v4 부터는 unkown도 가능하다)가 되는 것이다.

 

🥕 일부 라이브러리들에서는 Error 객체를 상속받은 새로운 커스텀 Error 객체를 만들어 사용하는데, 이 경우 try catch로 잡아낸 error가 제대로 타입스크립트의 지원을 받지 못하는 문제점이 발생한다.

(물론, 기존의 Error 역시 any 타입으로 처리 해버리는 문제 또한 있다)

class CustomError extends Error {
  consoleError() {
    console.log("this is CustomError ~~~");
    return "🌽";
  }
}

function errorTest() {
  throw new CustomError("에러입니다. 🍌");
}

try {
  errorTest();
} catch(err) {
  console.log("err @ ", err.consoleError());
}

위에서 catch의 인자 err은 any 타입이 되어버린다.

 

이와 같은 경우에 다음과 같이 err에 정확이 타입을 지정하면 되는 것이 아니냐고 할 수도 있다.

try {
  errorTest();
} catch(err: CustomError) {
  console.log("err @ ", err.consoleError());
}

물론 이렇게 사용할 수도 있지만, 완벽한 해결책은 되지 않는다.

 

자바스크립트에서 throw로 던질 수 있는 값은 Error 객체만 있는 것은 아니기 때문이다. (사실 모든 값을 throw할 수 있다)

function throwSomething(n: number) {
  if (n > 0) {
    throw "hello world"; // 에러가 아니어도 던질 수 있다
  } else {
    throw new Error("Error ~!@#$%");
  }
  console.log("function End");
}

try {
  throwSomething(-1);
} catch (e) {
  console.log("ERROR ---\n🍉", e); // 에러 발생
}

try {
  throwSomething(1);
} catch (e) {
  console.log("ERROR ---\n🍉", e); // 문자열 hello world가 출력된다
}

위의 코드에서 에러가 발생하는 첫 번째 코드 뿐만 아니라, 두 번째 코드에서도 catch에 문자열 값이 전달되어 에러처럼 처리되어 버린 것을 확인할 수 있다.

 

따라서, 타입스크립트에서 에러를 처리할 땐 주로 instanceof를 사용한다.

function throwSomething(n: number) {
  if (n > 0) {
    throw "hello world"; // 에러가 아니어도 던질 수 있다
  } else {
    throw new Error("Error ~!@#$%");
  }
  console.log("function End");
}

try {
  throwSomething(1);
} catch (e) {
  if(e instanceof Error) {
     console.log("ERROR ---\n🍉", e); 
  } else {
     console.log("안녕 세계.");
  }
}

위의 코드에서는 에러 객체를 throw하지 않기 때문에, 에러 콘솔을 출력하지 않는 것을 확인할 수 있다.

 

instanceof를 통해서 여러 개의 Error 객체를 구별할 수 있다.

class CustomError1 extends Error {
  consoleError() {
    console.log("CustomError 🐬");
  }
}

class CustomError2 extends Error {
  public errorMessage = "Is Error 🌞";
}

function errorGenerator() {
  const random = Math.floor(Math.random() * 10) + 1;
  console.log(random);
  if (random % 2 === 0) {
    throw new CustomError1();
  } else {
    throw new CustomError2();
  }
}

try {
  errorGenerator();
} catch (error) {
  if (error instanceof CustomError1) {
    error.consoleError();
  } else if (error instanceof CustomError2) {
    console.log(error.errorMessage);
  } else {
    console.log(error); // any
  }
}

랜덤 값이 홀짝인지에 따라 다른 커스텀 에러 객체가 생성되는데, instanceof를 통해서 이를 분기처리하여 따로 관리할 수 있다.

 

 

⛈ 추가적으로 Axios의 AxiosError를 사용하여 타입스크립트 Error 예제를 만들어보았다.

import axios, { AxiosError } from "axios";

const apiFn = async () => {
  try {
    const res = await axios("없는도메인.com");
    console.log(res);
  } catch (err) {
    if (err instanceof AxiosError) {
      console.log("is Axios Error ⛈", err.isAxiosError);
    } else {
      console.log("is not Axios Error 🌞", err);
    }
  }
};

apiFn();

위에서 만약 err가 AxiosError라면, Error객체를 상속받은 AxiosError가 추가적으로 구현한(기존 Error객체에는 없는) isAxiosError값이 있으므로 타입스크립트에서 자동완성을 지원해준다.

 

하지만, axios에서는 isAxiosError 라는 메서드를 지원하기에, 이를 통해서 처리하는 방법이 더 정석적인 라이브러리 사용법인 것 같다.

import axios, { isAxiosError } from "axios";

axios
  .get("없는도메인.com")
  .then(console.log)
  .catch((err) => {
    if (isAxiosError(err)) {
      console.log(err.isAxiosError); // true
    }
  });

위와 같이 err 객체를 isAxiosError 메서드를 통해서 검사할 수 있다.

 

✨ class 문법은 ES6부터 새로 생긴 문법이기에, 에제에 사용된 class나 instanceof등의 키워드를 타입스크립트에서 제대로 사용하기 위해서는 자바스크립트 ES6 이상으로의 컴파일이 필요하다.

MDN에서 classinstanseof의 브라우저 호환성을 확인해볼 수 있다. IE가 아니라면,  환경에서 사용이 가능하다.

 

🎡 참고 자료

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Error/Error

 

Error() 생성자 - JavaScript | MDN

Error 생성자는 오류 객체를 생성합니다.

developer.mozilla.org

https://stackoverflow.com/questions/69577451/how-do-you-type-an-error-property-in-a-catch-block-in-typescript

 

How do you type an error property in a catch block in TypeScript?

I have this code: import axios, {AxiosError} from "axios"; try { some request } catch(err:AxiosError) { console.log(error.response) // Doesn't work console.log(error.response?.data?.

stackoverflow.com