[FIFAPulse] 개발기록 - TypeScript 에서 catch 의 error 객체 사용 하기

조민호·2023년 8월 14일
0
post-thumbnail
post-custom-banner

이 포스팅은 개인 프로젝트를 진행하면서 공부하게 된 내용 임에도 불구하고
해당 상황에 대한 문제 해결 방식이 아닌 , 기본 개념을 설명하는 방식으로 작성합니다


JS에서는 catch문에서 인자로 전달받는 error에 대해 아무런 타입이 필요가 없었지만

TS에서는 타입 지정이 필요합니다

[typescript] Object is of type 'unknown'.ts(2571) (error object)
  • 기존에는 catch로 넘어온 에러 객체의 타입이 any 타입 이었기 때문에, JS 처럼 사용해도 에러가 발생하지 않았습니다.

  • 하지만 타입스크립트 v4.4 부터는 에러 객체의 타입이 unknown 타입으로 정의 되어서 JS 처럼 바로 에러 객체에 접근하게 되면 에러가 발생하게 됩니다

throw 문을 이용해 에러 발생을 시킬 때 에러에는 아래와 같이 그 어떤 타입도 들어갈 수 있기 때문에

throw "What the!?";
throw 7;
throw { wut: "is this" };
throw null;
throw new Promise(() => {});
throw undefined;

아래처럼 catch에 넘어오는 에러 객체의 타입을 지정할 수도 없습니다

catch (error: {
    status: string;
    data: string;
  })


이에 대한 간편한 해결책으로 type assertion이 있습니다

반환된 에러 객체의 타입을 지정하고 catch문 안에서 사용할 때 해당 타입으로 단언하고

사용하는 것입니다

그렇지만 알다시피 TS에서 type assertion은 그리 좋은 선택지가 아닙니다

unknown 타입일 때 가끔 as 연산자를 사용하긴 하지만, 사실 TS에서 as 도 any 만큼 지양하는것이 옳습니다

그렇다면 어떻게 해결해야 할까요?

이럴때 가장 좋은 방법은 instanceof 를 이용하여 각 에러 객체 타입에 따른
타입 가드를 하는 것입니다




모든 에러 객체에 대해 통합적으로 적용할 경우

try 부분에서 발생한 에러가 발생하게 되면 아래와 같이 작성할 수 있습니다.

catch로 넘어온 값이 표준 Error 객체인지 확인을 하고 , 기본 프로퍼티인 .message를 출력하는 것입니다

여기서 , 보통 에러 객체라고 하면 아래의 종류들이 있는데

  • new Error() 와도 같은 JS 표준 에러 객체 종류 (ReferenceError , SyntaxError , TypeError 등..)

  • 각 라이브러리 마다 사용되는 에러 객체 (Axios 사용시 , HTTP 요청과 관련된 에러 정보를 담고 있는 AxiosError 객체)

  • 커스텀 에러 클래스로 만든 객체

기본적으로 JS 표준 에러객체인 new Error()는 모든 에러의 프로토타입입니다.
즉 , 모든 에러 객체들은 Error 객체를 상속해서 사용하게 되므로
error instanceof Error 를 사용하면 모든 에러 객체가 true값이 되므로 모든 에러 종류에 대해 일괄적으로 처리할 수 있습니다

예를들어 각 에러 객체마다 구조가 다르겠지만

message프로퍼티의 경우 모든 에러 객체들이 상속받아 사용하므로 일괄적으로 사용할 수 있습니다



위의 로직을 모든 catch 블록에서 사용할 수 있는 유틸 함수로도 만들어줄 수 있습니다

💡 모든 에러 객체는 (커스템 에러 , HTTP 통신 라이브러리 에러 객체 등…) 전부 Error객체를 상속받는 것이므로 위의 error instanceof Error 에 들어오게 됩니다.

그렇지만 위처럼 하는 것은 그렇게 좋은 방법은 아닙니다

에러 객채의 구조가 전부 다 다르고 message프로퍼티만 사용하는것이 아니기 때문에

각 에러객체의 구조에 맞춰서 사용하는게 좋습니다




각 에러 객체들에 대해 조건부로 사용할 경우

error instanceof Error 가 아닌 , 각 에러 객체에 따라 다르게 적용합니다

ex ) error instanceof NicknameDuplicationError(커스텀에러)

만약 Axios를 사용한다고 가정 해 봅시다

Axios를 사용하게 되면 반환 되는 에러 객체는 JS 표준 에러 객체가 아닌

HTTP 클라이언트 라이브러리의 에러 객체인 AxiosError가 들어오게 됩니다

(자세한 설명은 catch 인자로 넘어온 에러 객체는 뭘까? )

객체의 프로퍼티는 다음과 같습니다.

  • response
    • status ,statusText , headers ,data
  • request
  • message
  • config

💡 위의 속성을 가진 에러 타입을 사용해야 하지만, 모든 속성을 처음부터 전부 기재하는 것보다 필요할 때마다 추가하는 것이 좋습니다.



현재 제가 저기서 사용하는 프로퍼티는 response , response.data , response.status 입니다.

그러므로 아래와 같이 진행해 보았습니다.

그렇지만 이 방법은 이상하게도 에러를 발생시킵니다.

왜냐하면 타입스크립트에서 인터페이스는 순전히 타입스크립트 문법이므로

컴파일 되면 코드가 사라지게 된다. 그러므로 instanceof 할 개체가 없어지기 때문입니다.

그렇지만 , 클래스는 자바스크립트에서도 있는 문법이라, 컴퍼일 돼도 코드가 남게 됩니다!

그래서 커스텀 에러 객체를 사용하려면 커스텀 에러 클래스를 사용해야 합니다

생성자에 사용된 부분을 보면

  • 커스텀 에러 객체라도 필수적으로 같이 선언 해 줘야 하는 프로퍼티들
    • super(message) : 전반적인 에러에 대한 메세지.
      new Error 객체에 존재하는 속성이며 부모 Error 클래스의 message 속성이 해당 문자열로 설정됩니다.
    • name : 에러 이름.
      이 역시 new Error 객체에 존재하는 속성이지만 Error 클래스 생성자는 message만 받으므로 name은 직접 할당해야 함
  • 실제로 반환된 Axios에러 객체의 일부
    • response : Axios를 사용하면서 반환된 에러 객체타입중 , 현재 사용하는 프로퍼티들


이제 위의 커스텀 에러 객체를 바탕으로 타입가드를 사용해서

에러 정보를 사용할 수 있습니다.


사실, Axios는 전용 에러 객체인 AxiosError 객체가 따로 존재합니다

그러므로 위처럼 직접 Axios에 대한 에러 객체를 만드는 것보다

아래처럼 AxiosError 객체를 직접 사용하는 것이 더 간편합니다.

catch (error) {
			if (error instanceof AxiosError) {
				 console.log(error.response?.status);
		     	 console.log(error.response?.data); 
				 ...
			}
}

그렇지만 Axios와 달리 , 만약 해당 상황에 따른 에러 객체가 존재하지 않는다면,
이땐 커스텀 에러 클래스를 직접 만들어서 적용할 수 있습니다.

예를 들어,

  • input 창에 입력된 닉네임을 바탕으로 계정 정보를 받아오는 비동기 API를 요청했는데
  • 중복된 닉네임에 대해 입력했다면 이에 따른 에러를 발생시켜야 합니다
  • super(message) : 전반적인 에러에 대한 메세지.
    new Error 객체에 존재하는 속성이며 부모 Error 클래스의 message 속성이 해당 문자열로 설정됩니다.
  • name : 에러 이름.
    이 역시 new Error 객체에 존재하는 속성이지만 Error 클래스 생성자는 message만 받으므로 name은 직접 할당해야 합니다
  • status 와 code 표준 Error 객체에는 포함되지 않은 사용자 정의 속성입니다.

아래는 사용 예시 입니다


커스텀 에러 객체는 어떻게 사용 할까?

자연스레 발생하는 에러( 변수 참조 에러 , HTTP통신 에러 등 ) 에서는

이미 이에 따른 내장 에러 객체가 catch의 error 객체에 전달됩니다.

그러므로 우리가 만든 커스텀 에러 객체를 사용하기 위해서는

조건에 따라 해당 에러를throw를 통해 명시적으로 에러를 발생시켜야 합니다.

예를 들어 input창에 상대방 닉네임을 입력하고 API 호출을 해야 하는데

현재 로그인된 내 닉네임을 입력했다면

throw 를 명시해서 NicknameDuplicationError 커스텀 에러를 직접 던질 수 있습니다.


출처 :

TypeScript에서 catch block error message 사용하기

📘 타입스크립트 커스텀 Error 처리하기

post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 10월 26일

좋은글 감사합니다.

답글 달기