[Javascript] 커스텀 에러 설정하기

박기영·2022년 12월 1일
1

Javascript

목록 보기
21/45

프로젝트를 진행하다보면 정말 다양한 예외 처리를 해줘야한다.
여기서 예외는 입력값에 대한 검증일 수도 있고, 누락 여부의 확인일 수도 있고,
개발자의 문법 에러일 수도 있다.
보통 new Error()를 사용하여 에러를 throw하는 경우가 많다.
그런데...마냥 new Error()만 쓰자니 어떤 에러인지 구분이 잘 안된다.
내가 직접 이 에러는 이런 에러다~ 라고 명시할 수는 없을까?
이번에는 에러를 더 자세하게 분류할 수 있는 커스텀 에러에 대해서 알아보자.

구조

└── src
    ├── App.js
    ├── BridgeGame.js
    ├── BridgeMaker.js
    ├── BridgeRandomNumberGenerator.js
    ├── Game.js
    ├── Player.js
    ├── constant
    │   └── Constants.js
    ├── error
    │   ├── CommandError.js
    │   ├── MovingError.js
    │   ├── SizeError.js
    │   └── ValidationError.js
    ├── validation
    │   ├── CommandValidation.js
    │   ├── MovingValidation.js
    │   └── SizeValidation.js
    └── view
        ├── InputView.js
        └── OutputView.js

여기서 다룰 것은 error, validation 폴더이다.

어떤 Error인지 정하기

// error/ValidationError.js
class ValidationError {
  constructor(message) {
    this.message = message;
  }
}

module.exports = ValidationError;

어떤 에러인지를 알려줄 최상위 클래스이다.
이 클래스를 상속하는 것으로 상속받은 클래스에서 발생하는 에러가 validation에 관한 에러라는 것을 알 수 있다.
이 부분에 대해서는 더 자세하게 명시할 수 있는데, 이는 게시글 하단 참고 자료를 보면 더 자세하게 알 수 있다.
필자는 에러 표시를 사용자에게 직접 보여줘야하기 때문에 이 부분은 생략했다.

가령 예를들어, validation에 관한 에러가 아니라 문법에 관한 에러를 나타내고 싶다면,
SyntaxError 등으로 생성해볼 수 있겠다.

어떤 입력값에 대한 Error인지 정하기

// error/SizeError.js
const ValidationError = require('./ValidationError');

class SizeError extends ValidationError {
  constructor(message) {
    super(message);
    this.name = 'SizeError';
  }
}

module.exports = SizeError;

ValidationError를 상속하는 것으로 이 에러 클래스가 의미하는게 입력값 검증이라는 것을 알 수 있다.
클래스명만 봐도 size라는 입력값에 대한 validation 에러라는걸 알 수 있다.

super를 사용하여 ValidationError에 에러 메세지를 전달했다.

예외 처리 진행하기

// validation/SizeValidation.js
const SizeError = require('../error/SizeError');
const { ERROR, GAME } = require('../constant/Constants');

class SizeValidation {
  #size;

  constructor(size) {
    this.#size = size;
  }

  checkError() {
    this.checkRange();
    this.checkStartWithZero();
    this.checkOnlyNumber();
  }

  checkRange() {
    const sizeNumber = Number(this.#size);

    if (sizeNumber < GAME.MINIMUM_RANGE || sizeNumber > GAME.MAXIMUM_RANGE) {
      throw new SizeError(ERROR.OUT_OF_RANGE);
    }
  }

  checkStartWithZero() {
    if (this.#size[0] === GAME.STRING_ZERO) {
      throw new SizeError(ERROR.START_WITH_ZERO);
    }
  }

  checkOnlyNumber() {
    const regex = /^\d+$/g;

    if (!regex.test(this.#size)) {
      throw new SizeError(ERROR.NOT_ONLY_NUMBER);
    }
  }
}

module.exports = SizeValidation;

size 입력값에 대한 예외 처리를 담당하는 클래스이다.
특정 조건에서 예외가 발생하면 new Error() 대신 new SizeError()를 던진다.
코드 상을 어떤 에러인지 명확하게 알 수 있게되었다.

new SizeError()에 들어가는 에러 메세지는 SizeError에서 super를 통해 ValidationError까지 전달된다.

일부러 예외 상황을 발생시켜보자.

참고 이미지

message에는 상수화하여 new SizeError()에 넣어줬던 문자열이 출력된다.
nameSizeErrorconstructor에서 생성했던 this.name이 출력된다.

사실, SizeError를 던졌기 때문에 당연하게도 생성자에 들어있는 값들이 출력되는 것이다.

아무튼, 중요한 것은 어떤 에러가 발생했는지 이름을 통해 더 세세하게 구분할 수 있다는 것이다.

과정

Game.js에서 입력값에 대한 SizeValidation을 실행한다.
SizeValidation에서는 SizeError에 어떤 예외 상황인지를 전달한다.
SizeErrorValidationError를 상속받아, 유효값 검증에 대한 에러라는 것을 알 수 있다.

에러 상황은 다양할 수 있다. 따라서 ValidationError 외에도 다른 에러 클래스를 생성할 수 있다.
마찬가지로 size라는 입력값에 대한 예외 처리는 다양한 상황이 있을 수 있다.
여기서는 SizeError로 묶여있지만, PropertyError 등의 이름으로 더 다양한 상황에 적용 가능한 클래스를 만들 수도 있겠다.

그렇게되면 이런 식의 참조 구조가 될 것으로 예상된다.

SizeValidation -> sizeError -> PropertyError -> ValidationError

검증에 대한 에러이며, 프로퍼티 검증 중 발생한 에러이며, 그 프로퍼티는 size이다.
이런 식으로 이해할 수 있겠다.

참고 자료

javascript-info : 커스텀 에러와 에러 확장

profile
나를 믿는 사람들을, 실망시키지 않도록

0개의 댓글