원티드 프리온보딩 챌린지 - 타입스크립트 리팩토링 일지
타입스크립트는 변수를 선언하면 타입을 알아서 추론한다.
이때 중간에 any
가 들어오거나 타입 단언(as
, !
등)이 잘못 사용되면 타입 추론에 빈틈이 생기게 되고, 런타임 에러가 생길 수 있다.
const foo = (hi: string, hello: string) => {
const hiHello: any = hi + hello;
return hiHello;
}
따라서 any
는 제한적인 상황에서만 쓰는 것이 좋은데, 다음 예시에서처럼 인자로 받은 값이 number
타입일 때만 true를 리턴하는 함수에서는 인자의 타입을 any로 지정해 주는 것이 적절하다.
const isNumber = (value: any): value is number => {
return typeof value === "number"
}
try-catch
로 에러 핸들링을 할 때, error type을 any로 지정해도 된다는 글을 어디선가 본 기억이 있었다.. 그래서 이번에 처음 마이그레이션 할 때 error 타입을 모조리 any로 박아두었다.
하지만 이렇게 error를 any로 지정해놓을 경우, 발생한 에러의 타입이 통신 관련한 에러가 아니라면 에러를 무한정 내놓게 되는 상황이 발생할 수 있다. 뭔가 에러가 났는데? 그 에러의 타입이 이상해서? 또또 에러..
// 강의자료에 박제된 나의 코드이다 (불명예)
const deleteTodo = async (e: React.MouseEvent) => {
e.preventDefault();
try {
await TodoApi.delete(id);
getTodos();
} catch (err: any) {
alert(err.response.data.details);
}
};
그럼 에러 타입을 어떻게 지정해야 할까? catch 문은 throw 문에서 던지는 무언가를 잡는다. 그런데 throw 문이 던질 수 있는 건 Error 객체 뿐만이 아니다(throw - MDN). 따라서 타입스크립트는 catch (error)
에서 error 타입을 unknown
으로 추론하게 된다.
catch (error: Error) {
reportError({ message: error.message });
}
이런식으로 에러에 타입을 지정할 경우 컴파일 에러가 발생하는 이유가 바로 그것..
이런 경우 error에 타입을 직접 지정하지 않고, 타입에 따른 분기를 만들어 처리하는 type narrowing
으로 해결할 수 있다!
// 리팩토링 후 코드
catch (error) {
if (error instanceof Error) {
toast.error(error.response?.data.details);
}
}