ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [타입스크립트 Enum] What are you Enum!?
    front-end/Javascript&Typescript 2023. 7. 8. 00:14

    Enum 이란?

    Pure Javascript 엔 존재하지 않는 기능이며 , 여러 개의 관련된 상수 값을 그룹화하는 사용됩니다. enum 명명된 상수 집합을 정의하며, 상수는 고유한 이름(식별자) 연결된 값을 가집니다.

     

    enum Days {
      Monday,
      Tuesday,
      Wednesday,
      Thursday,
      Friday,
      Saturday,
      Sunday
    }

     

    위의 예제에서 Days enum 이름이고, Monday, Tuesday, 등은 enum 멤버입니다.

    value에 아무것도 할당하지않으면 , enum은 0부터 시작하여 자동으로 증가하는 값을 갖게 됩니다.

    따라서 Days.Monday 값은 0이며, Days.Tuesday 값은 1입니다.

    또한 enum에 직접 값을 할당할 수도 있습니다.

     

    Enum을 언제 왜 쓰는지?

    1. 상수 값 그룹화: enum은 관련된 상수 값을 그룹화하여 가독성을 높일 수 있습니다. 예를 들어, 요일을 나타내는 경우 Days.Monday, Days.Tuesday 등으로 사용하면 코드의 의도를 명확하게 전달할 수 있습니다.

     

    2. 선택적인 할당: enum 멤버는 숫자 값을 가지므로, 특정 멤버에 값을 할당하여 사용할 수 있습니다. 이를 통해 특정 상수 값을 나타내는 역할을 수행할 수 있습니다.

     

    3. 스위치 문과 함께 사용: enum 주로 스위치 문과 함께 사용됩니다. 스위치 문은 enum 멤버에 대한 동작을 정의하는 유용합니다. 이를 통해 가독성이 높은 코드를 작성할 있습니다.

     

    저 또한 자주 사용했었던 경혐이 ,아래와 같이 조건 별로 맞는 화면을 렌더링 해야할때 enum의 열거형을 이용해 useState와 함께

    조건에 따른 화면 렌더링을 자주 이용했었습니다.

     

    enum RENDER_BY_STATE {
      FIRST,
      SECOND,
      THIRD,
    }
    
    const [state, setState] = useState(RENDER_BY_STATE.FIRST);
    
    if (something === 'something') {
      setState(RENDER_BY_STATE.SECOND);
    }
    if (somethingElse === 'somethingElse') {
      setState(RENDER_BY_STATE.THIRD);
    }
    
    const renderByState = () => {
      switch (state) {
        case RENDER_BY_STATE.SECOND:
          return (
            <div>This is Second State.</div>
          );
        case RENDER_BY_STATE.THIRD:
          return (
            <div>This is Third State.</div>
          );
        default:
          return (
            <div>This is First State.</div>
          );
      }
    };

     

     

     

    주의: enum의 Key 값에 numeric 타입을 선언하면 아래이미지 처럼 에러가 납니다.

     

     


    Enum 문제점

     

    1. Tree Shaking 문제

    대표적으로 Tree Shaking 문제가 있습니다.

    TypeScript enum JavaScript 변환될 , 실제 사용되지 않는 열거형 멤버도 포함될  있습니다. 이는 Tree Shaking(불필요한 코드 제거) 같은 최적화 기술을 방해할  있습니다. 따라서, enum 사용하면 번들 크기가 증가하고 성능이 저하될  있습니다.

     

    Tree Shaking JavaScript 번들에 포함된(사용되지 않는) 불필요한 코드를 제거하는 최적화 기술입니다.  애플리케이션을 개발할 , 프로젝트의 모든 코드를 하나의 번들로 묶어서 배포하는 경우가 많습니다. 그러나 대규모 프로젝트에서는 번들에 포함된 코드 양이 많을  있고, 사용되지 않는 코드까지 포함되어 번들의 크기가 커지게 됩니다.

     

     

    2. 접근 문제

    아래의 이미지 같이 Object.values 로 enum을 접근 해보면 요일과 열거 숫자들을 같이 찍히는 모습이 보입니다.

    이렇게 찍히는거나 마찬가지죠. 객체의 값에 접근할 경우면 최악의 경우입니다.

     

    자바스크립트 객체로 표현 하자면 아래와 같은 형태입니다.

    로그 결과가 똑같이 나오죠?

     

    log 함수에 name 과 days의 파라미터를 넣고 name엔 string , days엔 enum Days의 타입으로 지정해줬습니다.

    위 코드는 별 문제없이 log 함수에 접근해서 로그가 정상적으로 출력됩니다.

     

    아래 코드는 enum의 단점이라고 말하기엔 좀 애매하지만, enum의 멤버로 접근하면 에러가 납니다.

    enum의 멤버에 접근하려면 Days.Friday 이런식으로 접근해야 합니다. 

    타입스크립트는 타입의네이밍을 신경쓴기보다 타입스트립트의 runtime value의 대해서 신경을 씁니다.

    그래서 타입스크립트는 Days.Friday로 접근하던지 , Days.Friday 의 멤버인 '금요일' 신경을 쓰지않아야합니다. 왜냐하면 둘의 값은 똑같기 때문이죠.

    하지만 Enum은 타입스크립트의 rule 을 약간 깹니다. 왜냐면 Enum은 타입스크립트의 네이밍을 신경을 쓰기 때문이죠.

    반대로 Enum을 좋아하는 유저들이 리팩토링이 쉽기때문에 benfit을 얻을 수 있긴합니다.

    추가설명 : 

    타입스크립트는 주로 컴파일 타임에 타입을 체크하고 타입 안정성을 유지하는 것이 목표입니다. 런타임에 실제 값에 대한 처리는 상대적으로 보조적인 역할을 합니다.

    따라서 타입스크립트에서는 주로 타입 정보와 타입 체크에 중점을 둡니다. Days.Friday와 '금요일'은 동일한 값을 나타내지만, 타입스크립트는 이들을 다른 타입으로 처리합니다. Days.Friday는 Days 열거형의 멤버이며, '금요일'은 문자열 값입니다.

    하지만 enum은 타입스크립트의 타입 규칙을 약간 깨는 요소 중 하나입니다. enum은 타입과 값의 네이밍을 모두 고려합니다. Days.Friday는 타입스크립트에서는 Days 타입이지만 동시에 '금요일'이라는 값으로 평가됩니다. 이는 일종의 예외적인 상황으로 볼 수 있습니다.

    enum을 좋아하는 사람들은 enum이 타입과 값의 관계를 한데 묶어 리팩토링과 유지 보수를 용이하게 만들어 준다고 주장합니다. enum은 타입스크립트의 정적 타입 체계를 유지하면서도 값에 대한 의미를 표현할 수 있는 간편한 방법을 제공합니다.

    따라서, 말씀하신 내용은 맞는 말이라고   있습니다. 타입스크립트는 주로 타입에 신경을 쓰지만, enum 값과 타입의 네이밍을 함께 다루는 특수한 경우입니다.


    const enum

    const enum을 사용하면 , 컴파일 할때 enum의 가장 큰 문제인 Tree shaking이 보완된거같습니다.

    아래 코드와 같이 컴파일 후 어떠한 코드도 보이질 않습니다.

    const enum enum 변형 형태로, enum 멤버를 상수로 처리하여 번들에 실제 값으로 인라인화합니다. , const enum 컴파일된 JavaScript 코드에서 enum 제거하고, 해당 enum 멤버를 사용한 곳에 직접 값을 삽입합니다. 이로 인해 번들 크기를 줄일  있으며, 런타임에 추가적인 객체 생성 없이 상수 값에 접근할  있습니다.

     

    하지만 const enum에도 가지 이슈가 있습니다. 가장  이슈는 사용된 위치에서 enum 값이 아닌 실제 상수 값으로 inline화 된다는 것입니다. 이는 enum 사용하는 외부 코드에서 enum 변경 사항에 영향을 받지 않는다는 장점이 있지만, enum 사용된 모든 코드를 다시 컴파일해야만 enum 변경이 반영되는 단점이 있습니다. 이는 enum 변경이 전체 애플리케이션에서 일관되게 적용되지 않을  있다는 것을 의미합니다.


    as const

    그래서 도대체 enum , const enum 말고 무엇을 써야하느냐...

    "as const"를 사용하여 객체를 선언하면 객체의 속성들은 해당 값에 대한 타입 정보를 보다 정확하게 유지할 수 있습니다.

     

    아래 코드는 위 예시에서 봤던거처럼 네이밍보다 value의 초점을 둬서 '금요일' 이라는 value로 파라미터에 접근을 해도 에러가 안나고

    정상적으로 로그가 출력 되는것을 볼수있습니다 .

     

    아래의 코드중 제네릭 코드에 대해서 설명

    더보기

    제네릭은 타입스크립트에서 재사용 가능한 코드를 작성할 때 타입 안정성을 유지하기 위해 사용되는 기능입니다.

    여기서 <T>는 제네릭 타입 매개변수로 사용되며, T는 임의의 타입을 나타냅니다. 이렇게 제네릭을 사용하면 여러 타입에 대해 일반화된 코드를 작성할 수 있습니다.

    type DaysValues<T> = T[keyof T];는 Days 객체 타입에 대한 제네릭 타입 매개변수 T를 받아 T 타입의 값들을 추출하는 타입을 정의하는 구문입니다. keyof T는 T 타입의 모든 속성(키)을 유니온 타입으로 추출하는 역할을 합니다. T[keyof T]는 T 타입의 모든 속성에 해당하는 값의 유니온 타입을 나타냅니다.

    즉, DaysValues<typeof Days>는 typeof Days가 가지고 있는 속성(키)에 해당하는 값들의 유니온 타입을 나타냅니다. 이 경우 typeof Days는 { Monday: '월요일', Tuesday: '화요일', ... }와 같은 객체 타입이므로, DaysValues<typeof Days>는 '월요일' | '화요일' | ...와 같은 유니온 타입이 됩니다.

    이렇게 정의된 DaysValues 타입은 DaysMember라는 타입 별칭으로 사용되며, Days 객체의 속성 값들의 유니온 타입을 나타내게 됩니다. 따라서 DaysMember는 '월요일' | '화요일' | ...와 같은 타입이 됩니다.

    이와 같이 제네릭 타입 매개변수를 사용하여 타입 추론이나 타입 변환을 일반화할 수 있고, 코드의 재사용성과 유연성을 높일 수 있습니다.

     

     

     

    일반적으로 자바스크립트에서 객체를 선언하면 mutable 하는것은 다들 알고 계실겁니다.

    const obj = {
      name: 'kwangmin',
      bornAt:1993
     }
     
     obj.name = 'john';
     
     console.log(obj.name);
     // 'john'


    하지만 "as const"를 사용하면 객체의 모든 속성들이 리터럴 타입으로 취급되고, 변경이 불가능한 상수로 선언됩니다.

    아래 코드를 보면 readonly 라고 되어있죠? 그리고 객체의 값을 변경하려고 해도 에러가 납니다.

     

    enum을 대체하기 위한 "as const" 사용은 상황에 따라 유용할  있습니다. 위에서 말했다시피 enum은 타입과 값을 모두 고려하는 특성을 갖지만, "as const"를 사용하면 리터럴 타입을 갖는 불변 객체를 생성하여 유사한 효과를 얻을  있습니다. 이를 통해 코드의 가독성, 유지 보수성, 타입 안정성 등을 개선할  있습니다.'

     

    결론은 "as const" "enum" 대체하기 위한 가지 방법입니다. "enum" 타입과 값의 관계를 표현할 있지만, "as const" 사용하여 리터럴 타입의 불변 객체를 생성하면 비슷한 효과를 얻을 있습니다

     

    잘못된 내용이 있으면 댓글로 언제든지 알려주시길 바랍니다.

    Reference

    https://www.youtube.com/watch?v=jjMbPt_H3RQ 

     

Designed by Tistory.