반응형
예외 반환
TypeScript는 자바가 아니며 throws 문을 지원하지 않습니다.
참고로 throws 문은 메서드가 어떤 종류의 런타임 예외를 발생시킬 수 있는지 알려주어서 해당 메서드의 사용자가 발생 가능한 에러를 적절하게 처리할 수 있도록 도와줍니다.
하지만 유니온 타입을 이용해 비슷하게 흉내 낼 수 있습니다.
function ask() {
return prompt("생일 언제임?");
}
// 커스텀 에러 타입
class InvalidDateFormatError extends RangeError{}
class DateISInTheFutureError extends RangeError{}
/**
*
* @throw {InvalidDateFormatError} : 사용자가 생일을 잘못 입력함
* @throw {DateISInTheFutureError} : 사용자가 생일을 미래 날짜로 입력함
*/
function parse(birthday: string): Date | InvalidDateFormatError | DateISInTheFutureError {
let date = new Date(birthday);
if (!isValid(date)) {
throw new InvalidDateFormatError("YYYY/MM/DD 로 입력하셈여");
}
if(date.getTime() > Date.now()){
throw new DateISInTheFutureError('타임로드 했닝?')
}
return date;
}
이제 이 메서드 사용자는 모든 세 가지 상황을 처리해야 하며 그렇지 않으면 컴파일 타임에 TypeError가 발생합니다.
function ask() {
return prompt("생일 언제임?");
}
// 커스텀 에러 타입
class InvalidDateFormatError extends RangeError{}
class DateISInTheFutureError extends RangeError{}
/**
*
* @throw {InvalidDateFormatError} : 사용자가 생일을 잘못 입력함
* @throw {DateISInTheFutureError} : 사용자가 생일을 미래 날짜로 입력함
*/
function parse(birthday: string): Date | InvalidDateFormatError | DateISInTheFutureError {
let date = new Date(birthday);
if (!isValid(date)) {
throw new InvalidDateFormatError("YYYY/MM/DD 로 입력하셈여");
}
if(date.getTime() > Date.now()){
throw new DateISInTheFutureError('타임로드 했닝?')
}
return date;
}
// 입력한 날짜가 유효한지 검사
function isValid(date: Date) {
return (
Object.prototype.toString.call(date) === "[object Date]" &&
!Number.isNaN(date.getTime())
);
}
let result = parse(ask())
if(result instanceof InvalidDateFormatError){
console.error(result.message)
} else if (result instanceof DateISInTheFutureError){
console.error(result.message)
} else {
console.info('날짜는', result.toISOString)
}
이상으로 TypeScript는 타입 시스템을 활용하여 다음을 수행했습니다.
- parse의 시그니처에 발생할 수 있는 예외를 나열했습니다.
- 메서드 사용자에게 어떤 에러가 발생할 수 있는지 전달했습니다.
- 메서드 사용자가 각각의 에러를 모두 처리하거나 다시 던지도록 강제했습니다.
let result = parse(ask())
if(result instanceof Error){
console.error(result.message)
} else {
console.info('날짜는', result.toISOString)
}
물론 메모리 부족 에러나 스택 오버플로 예외 등으로 프로그램이 여전히 크래시 될 가능성은 남아있지만 현실적으로 이런 에러는 개발자가 대응할 수 있는 여지가 별로 없습니다.
이 방식은 상당히 단순하고 대단한 자료구조도 사용하지 않습니다.
하지만 API 사용자에게 실패 유형과 추가 정보를 얻을 수 있는 길을 알려주기에 충분합니다.
한편 에러를 던지는 연산을 연쇄적으로 호출하거나 중첩하면 코드가 지저분해진다는 단점이 있습니다.
예를 들어 T | Error1을 반환하는 함수를 이용하는 모든 호출자 함수는 두 가지 선택지 중 하나를 고를 수 있습니다.
- 명시적으로 Error1을 처리합니다.
- T를 처리하고 Error1은 호출자 함수의 사용자가 처리하도록 전달합니다. 하지만 이 방법을 자주 사용하면, 최종 사용자가 처리해야 할 에러의 종류가 크게 늘어날 수 있습니다.
function x(): T | Error1 {
// 블라 블라
}
function y():U | Error1 | Error2 {
let a = x()
if(a instanceof Error){
return a
}
// a로 어떤 동작을 수행
}
function z(): U | Error1 | Error2 | Error3 {
let a = y()
if(a instanceof Error){
return a
}
// a로 어떤 동작을 수행
}
이 방식은 조금 복잡한 대신 안전성이 뛰어납니다.
반응형
'👶 TypeScript' 카테고리의 다른 글
비동기 프로그래밍, 동시성과 병렬성 (0) | 2023.01.23 |
---|---|
에러 처리 - Option 타입 (0) | 2023.01.23 |
에러 처리 - 예외 던지기 (0) | 2023.01.23 |
에러 처리 - null 반환 (0) | 2023.01.22 |
프로토타입 안전하게 확장하기 (0) | 2023.01.22 |