타입스크립트 꽝꽝

[TypeScript] Java처럼 enum 사용하기

bimppap 2022. 2. 9. 10:31

 

문제

자바를 쓸 때 enum으로 열거형 상수를 줄곧 사용했었다.

// 추억의 로또 미션~
public enum WinningBoard {
    ZERO(0, 0, ""),
    FIFTH(3, 5_000, "3개 일치"),
    FOURTH(4, 50_000, "4개 일치"),
    THIRD(5, 1_500_000, "5개 일치"),
    SECOND(5, 30_000_000, "5개 일치, 보너스 볼 일치"),
    FIRST(6, 2_000_000_000, "6개 일치");

    private final int hitCount;
    private final int reward;
    private final String message;

    WinningBoard(int hitCount, int reward, String message) {
        this.hitCount = hitCount;
        this.reward = reward;
        this.message = message;
    }
  }

TypeScript에서도 이처럼 enum을 쓸려고 했는데 상수처럼 쓰이질 않아서 다른 방법이 있나 찾아보게 되었다.

 

해결 과정

(1) TypeScript enum을 검색하자마자 제일 먼저 보이는 건 Tree-shaking을 이유로 사용하지 말라는 거였다.(;;)

 

TypeScript enum을 사용하지 않는 게 좋은 이유를 Tree-shaking 관점에서 소개합니다. - LINE ENGINEERING

안녕하세요. LINE Growth Technology UIT 팀의 Keishima(@pittanko_pta)입니다. 이번 글에서는 TypeScript의 enum을 사용하지 않는 편이 좋은 이유를 Tree-shaking 관점에서 소개하겠습니다.

engineering.linecorp.com

그래서 Union Type을 이용해 해결하려고 했으나 아래처럼 난관에 부딪혔다.

const WinningBoard: {
  [key: string]: { hitCount: number; fare: number; message: string };
} = {
  ZERO: { hitCount: 0, fare: 0, message: "" },
  FIFTH: { hitCount: 3, fare: 5_000, message: "3개 일치" },
  FOURTH: { hitCount: 4, fare: 50_000, message: "4개 일치" },
  THIRD: { hitCount: 5, fare: 1_500_000, message: "5개 일치" },
  SECOND: { hitCount: 5, fare: 30_000_000, message: "5개 일치, 보너스볼 일치" },
  FIRST: { hitCount: 6, fare: 200_000_000, message: "6개 일치" },
} as const;

type WinningBoard = typeof WinningBoard[keyof typeof WinningBoard];

export const findWinnings = (hits: number, bonus: boolean): WinningBoard => {
  if (hits === WinningBoard.SECOND.hitCount && bonus) {
    return WinningBoard.SECOND;
  }
  // const key = Object.keys(WinningBoard).find(k => WinningBoard[k].hitCount === hits);
  // if(key === undefined) {
  //     return WinningBoard.ZERO;
  // }
  // return... 여길 어떻게 하니...
};

 

value의 Properties를 비교하여 맞는 값을 찾은 후, 그 값을 가진 value를 리턴하는 방식으로 구현하려고 했으나... 내가 타입스크립트에 미숙한건지 타입스크립트에 그런 기능이 없는 건지 해결할 수 없었다. 🥲 아마도 열거형은 되나 상수처럼 못 쓰니 생긴 문제 아닐까 싶다.

 

switch나 else if로 해결하기엔 개발자 GAO가 있었기에 머릴 싸매다가 사수한테 SOS를 쳤다.

그리고 사수 曰... "우린 백엔드라 Tree-Shaking을 걱정할 필욘 없어요."

😮...

 

그리고 조졸두님의 블로그글을 공유 받았다. 타입스크립트에서 자바처럼 Enum을 쓸 수 있는 오픈소스 소개 및 사용 방법 글이었다.

 

ts-jenum 으로 응집력 있는 TS 코드 작성하기 (feat. EnumClass)

TypeScript의 Enum은 딱 열거형으로서만 사용할 수 있습니다. 다른 언어에서 Enum을 Static 객체로 사용해본 경험이 있는 분들이라면 이 지점이 굉장히 답답하다는 것을 느낄 수 있는데요. Java에서 Enum

jojoldu.tistory.com

 

최종

ts-jenum 을 사용한 이후론 일사천리였다.

import { Enum, EnumType } from 'ts-jenum';

@Enum('code')
export class WinningBoard extends EnumType<WinningBoard>() {
  static readonly ZERO = new WinningBoard('ZERO', 0, 0, '꽝🥲');
  static readonly FIFTH = new WinningBoard('FIFTH', 3, 5_000, '3개 일치');
  static readonly FOURTH = new WinningBoard('FOURTH', 4, 50_000, '4개 일치');
  static readonly THIRD = new WinningBoard('THIRD', 5, 1_500_000, '5개 일치');
  static readonly SECOND = new WinningBoard('SECOND', 5, 30_000_000, '5개 일치, 보너스볼 일치');
  static readonly FIRST = new WinningBoard('FIRST', 6, 200_000_000, '6개 일치');

  private constructor(
    readonly code: string,
    readonly _hitCount: number,
    readonly _reward: number,
    readonly _message: string,
  ) {
    super();
  }

  static findWinnings = (hits: number, bonus: boolean): WinningBoard => {
    if (WinningBoard.SECOND._hitCount === hits && bonus) {
      return WinningBoard.SECOND;
    }
    const winningBoard = WinningBoard.values().find((board) => board._hitCount === hits);
    if (winningBoard) {
      return winningBoard;
    }
    return WinningBoard.ZERO;
  };
}

고민이 있다면, 이렇게 타입스크립트를 자바처럼 사용해도 되나 싶긴 하다. 🤔

타입스크립트에서 자바스크립트의 장점을 살리는 방법도 공부해봐야겠다.