👶 TypeScript

에러 처리 - 예외 던지기

개발자 린다씨 2023. 1. 23. 09:00
반응형

예외 던지기

문제가 발생하면 null 반환 대신 예외를 던지겠습니다.

 

그러면 어떤 문제냐에 따라 대처가 가능할 수 있고, 디버깅에 도움 되는 메타 데이터도 얻을 수 있습니다.

function ask() {
  return prompt("생일 언제임?");
}

function parse(birthday: string): Date {
  let date = new Date(birthday);
  if (!isValid(date)) {
    throw new RangeError('YYYY/MM/DD 로 입력하셈여')
  }
  return date;
}

이제 이 코드를 사용할 때 전체 응용 프로그램이 크래시 되지 않도록 매끄럽게 처리하기 위해 주의해서 예외를 잡아야 합니다.

function ask() {
  return prompt("생일 언제임?");
}

function parse(birthday: string): Date {
  let date = new Date(birthday);
  if (!isValid(date)) {
    throw new RangeError("YYYY/MM/DD 로 입력하셈여");
  }
  return date;
}

// 입력한 날짜가 유효한지 검사
function isValid(date: Date) {
  return (
    Object.prototype.toString.call(date) === "[object Date]" &&
    !Number.isNaN(date.getTime())
  );
}

try {
  let date = parse(ask());
  console.info("생일은", date.toISOString());
} catch (e) {
  console.error(e.message);
}

다른 에러가 발생했을 때 무시하지 않도록, 처리하지 않은 에러는 다시 던지는 것이 좋습니다.

function ask() {
  return prompt("생일 언제임?");
}

function parse(birthday: string): Date {
  let date = new Date(birthday);
  if (!isValid(date)) {
    throw new RangeError("YYYY/MM/DD 로 입력하셈여");
  }
  return date;
}

// 입력한 날짜가 유효한지 검사
function isValid(date: Date) {
  return (
    Object.prototype.toString.call(date) === "[object Date]" &&
    !Number.isNaN(date.getTime())
  );
}

try {
  let date = parse(ask());
  console.info("생일은", date.toISOString());
} catch (e) {
  if (e instanceof RangeError) {
    console.error(e.message);
  } else {
    throw e;
  }
}

나중에 다른 개발자가 parse나 ask에서 또 다른 형태의 RangeError를 던질 수 있게 하려면 에러를 서브클래싱하여 더 구체적으로 표현하면 됩니다.

 

이런 방식으로 내가 만든 에러와 다른 개발자가 추가한 에러를 구분할 수 있습니다.

function ask() {
    return prompt("생일 언제임?");
  }
  
// 커스텀 에러 타입
class InvalidDateFormatError extends RangeError{}
class DateISInTheFutureError extends RangeError{}

  function parse(birthday: string): Date {
    let date = new Date(birthday);
    if (!isValid(date)) {
      throw new RangeError("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())
    );
  }
  
  try {
    let date = parse(ask());
    console.info("생일은", date.toISOString());
  } catch (e) {
    if (e instanceof DateISInTheFutureError) {
      console.error(e.message);
    } else if(e instanceof DateISInTheFutureError){
        console.error(e.message)
    } else {
      throw e;
    }
  }

이제 커스텀 에러를 이용하면 어떤 문제가 생겼는지 알려줄 수 있을 뿐 아니라 문제가 생긴 이유도 설명할 수 있습니다.

 

문제를 디버깅할 때 서버 로그를 함께 확인하거나, 사용자가 어떤 실수를 했으며 어떻게 문제를 해결할 수 있는지 알려주는 커스텀 에러 다이얼로그 등을 구현할 때 이런 구체적인 에러가 도움이 됩니다.

 

여러 동작을 try/catch 구문으로 감싸는 형태로, 연쇄적이고 중첩된 동작을 효율적으로 만들 수 있습니다.

 

이 코드는 어떻게 사용할 수 있을까요?

 

큰 try/catch 구문 안의 코드가 하나의 파일에 담겨 있고, 나머지 코드는 다른 라이브러리에서 이포트된 코드라고 가정합니다.

 

그렇다면 개발자는 특정 타입의 에러 또는 기존의 RangeError가 던져질 수 있다는 사실을 어떻게 알고 잡아서 처리할 수 있을까요?

 

그러려면 함수 이름에 명시하거나 문서화 주석(docblock)에 정보를 추가해야 합니다.

function ask() {
    return prompt("생일 언제임?");
  }
  
// 커스텀 에러 타입
class InvalidDateFormatError extends RangeError{}
class DateISInTheFutureError extends RangeError{}

/**
 * 
 * @throw {InvalidDateFormatError} : 사용자가 생일을 잘못 입력함
 * @throw {DateISInTheFutureError} : 사용자가 생일을 미래 날짜로 입력함
 */

  function parse(birthday: string): Date {
    let date = new Date(birthday);
    if (!isValid(date)) {
      throw new RangeError("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())
    );
  }
  
  try {
    let date = parse(ask());
    console.info("생일은", date.toISOString());
  } catch (e) {
    if (e instanceof DateISInTheFutureError) {
      console.error(e.message);
    } else if(e instanceof DateISInTheFutureError){
        console.error(e.message)
    } else {
      throw e;
    }
  }

 

반응형