...
타입스크립트 Error 처리 방법
자바스크립트에서는 어떤 값이든 에러로 던질수가 있다.
그러나 try catch 문에서 타입스크립트 에러를 처리하는데 아래와 같은 에러를 만나 본적이 있을 것이다.
[typescript] Object is of type 'unknown'.ts(2571) (error object)
기존에는 error: any 타입 이었기 때문에, 자바스크립트와 같이 사용해도 ts error가 발생하지 않았다.
하지만 타입스크립트 v4.4 부터는 error의 object가 unknown type으로 정의 되어서, ts error가 발생하는 것이다.
try {
// ...
} catch (err) {
console.error(err.message); // Object is of type 'unknown'.ts(2571)
}
그리고 추가적으로 써드파티 라이브러리를 사용할때, 일반적인 자바스크립트 코드 에러 외에, 라이버리 자체 에러 처리를 따로 처리 해줘야 하는 경우, 타입스크립트에서 이를 어찌 처리해야 되는지도 애매하다.
예를들어 다음과 같이 자바스크립트의 라이브러리인 axios 의 경우 자체적으로 요청 에러를 반환하는 error.response 객체가 존재한다.
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// 요청이 이루어졌으며 서버가 2xx의 범위를 벗어나는 상태 코드로 응답했습니다.
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
}
else {
// 오류를 발생시킨 요청을 설정하는 중에 문제가 발생했습니다.
console.log('Error', error.message);
}
console.log(error.config);
});
이번 시간에는 이 unknown 타입의 error 객체를 문제없이 처리하는 여러가지 방법과 더불어, 위의 axios 처럼 커스텀 라이브러리의 코드에서 자체 에러가 발생하면 어떻게 라이브러이 에러 객체를 처리하는지 방법에 대해 소개해 보겠다.
any 타입 강제변경
가장 직관적이면서도 간단한 해결책이다.
하지만 타입스크립트 개발자라면 그리 추천되는 방법이 아닌 것은 다들 알 것이다.
(async () => {
try {
await axios.get('/user/12345'); // axios 라이브러리 코드에서 에러가 발생할 경우
} catch (err: any) {
console.error(err.message); // 자체 자바스크립트 에러 객체
console.error(err.response.data) // axios 라이브러리 에러 객체
}
})();
타입 단언 하기
any 타입을 쓰지않고, 새로운 Error interface(혹은 type)을 정의하고, Type Assertion을 해주는 방법이 있다.
자바스크립트 axios 에러 객체를 보면 다음과 같이 프로퍼티가 구성되어 있었다.
그러면 이 속성 그대로 인터페이스로 타입을 정의해서 단언을 해주면 된다.
먼저 타입스크립트의 기본 Error 인터페이스를 상속받아, response 프로퍼티를 추가해주고 그안에, data, status, headers 프로퍼티를 추가해준다.
반드시 Error 인터페이스를 상속할 필요없고, 직접 그안에 있는 프로퍼티 타입을 직접 구현해줘도 되긴 하다.
interface CustomError extends Error {
// name: string;
// message: string;
// stack?: string; - Error 인터페이스 프로퍼티들을 직접 쓰거나 아니면 상속해준다.
response?: {
data: any;
status: number;
headers: string;
};
}
try {
await axios.get('/user/12345');
} catch (err: unknown) {
const customErr = err as CustomError; // 타입 단언한 것을 변수에 넣어서 뒤에서 자주 쓰이면 재사용 될 수 있게
console.error(customErr.response?.data);
console.error(customErr.response?.status);
console.error(customErr.response?.headers);
}
굳이 인터페이스 타입을 정교하게 만들 필요는 없다.
하나하나 일일히 타입을 지정하려면 머리 아프기 때문에, 당장 내가 코드에서 쓰느 것만 통과하게끔만 만들다가 나중에 다시 빨간줄 생기면, 그때그때마다 타입을 추가하는 식으로 구성하는 것이 좋다.
만일 변수 타입이 unknown 때 일때 어쩔수 없이 as 연산자를 사용하긴 하지만, 사실 as 도 any 만큼 지양하는것이 옳다.
as 를 붙인다는 것은 즉 사람이 직접 붙인다는 뜻인데, 사람의 작업에는 항상 실수가 일어나길 마련이기 때문에 언제 어디서 오류가 일어날수 있기 때문이다.
따라서 타입 단언을 사용하는 것보다는 정석 적인 방법인 타입 가드로 에러를 처리하는것이 옳다.
타입 가드 하기
가장 좋은 방법은 instanceof 를 이용하여 타입가드를 하는 것이다.
하지만 이상하게 빨간줄이 발생한다. 왜냐하면 인터페이스는 컴파일 되면 사라지기 때문에 instanceof 할 개체가 없어지기 때문이다.
클래스를 에러 객체로 이용하기
타입스크립트에서의 인터페이스와 클래스의 차이는, 컴파일 과정을 거친후 js 파일에 코드가 남냐 안남느냐의 차이이다.
인터페이스는 순전히 타입스크립트 문법이므로 컴파일 되면 코드가 사라진다.
반면에 클래스는 자바스크립트에서도 있는 문법이라, 컴퍼일 되도 코드가 남게 된다.
흔히 자바(Java)의 클래스로 생각하면 안된다. 자바스크립트의 클래스도 결국 거슬러 올라가면 똑같은 프로토타입 객체이기 때문에 이런식으로 사용이 가능한 것이다.
정리하자면 다음과 같이 클래스를 타입 객체로서 활용이 가능하다.
// 인터페이스는 컴파일되면 자바스크립트에서 사라지기 때문에 err instanceof CusomError 가 불가능하게 된다.
// 그래서 컴파일되도 남아있는 클래스를 타입으로 이용하는 방법을 쓰는 것이다.
class CustomError_Class extends Error {
response?: {
data: any;
status: number;
headers: string;
};
}
try {
await axios.get('/user/12345');
} catch (err: unknown) {
if (err instanceof CustomError_Class) {
console.error(err.response?.data);
}
}
총정리 하자면 다음과 같이 결론을 말할수 있다.
# 참고자료
제로초 타입스크립트 올인원
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.