[TypeScript] enum 타입과 활용

JulyK9·2023년 5월 19일
0

타입스크립트

목록 보기
1/1

왜 정리하는가?

프로젝트 연습중
타입스크립트는 정적 타입언어로
타입 설정을 통해 개발 오류를 잡아주는 기능에 비중을 두고 이해하고 있었다.

작성한 코드는 실제 컴파일후에 런타임에는 실행되지 않는 코드가
대부분으로 알고 있었는데..

enum 타입을 통해서는 실제 컴파일후에도
존재하는 속성값을 활용하는 경우를 확인하여
기본적인 부분을 조금 정리해보려 한다.

enums (열거형 타입)

enum 키워드를 사용하여 열거형 타입을 정의하며,
대표적으로 숫자 열거형문자열 열거형이 있다.

숫자 열거형

숫자 열거형은 타입의 멤버들이 값을 갖도록 해준다.

// EnumType.ts

export enum Direction {
  Up,
  Down,
  Left,
  Right,
}
// App.tsx

import { Direction } from "./EnumType";

export default function App() {
  return (
    <div className="App">
      <div>
        <span>Up : </span>
        {Direction.Up}
      </div>
      <div>
        <span>Down : </span>
        {Direction.Down}
      </div>
      <div>
        <span>Left : </span>
        {Direction.Left}
      </div>
      <div>
        <span>Right : </span>
        {Direction.Right}
      </div>
    </div>
  );
}

여기서 Up의 값은 0이 되고, Down은 1, Left는 2, Right는 3이 된다.

멤버의 값을 설정하여 초기화해주면,
그 뒤의 멤버들은 자동으로 증가된 값을 갖게 된다.

// EnumType.ts

export enum Direction {
  Up = 2, // 값을 2로 초기화하면
  Down,
  Left,
  Right
}

계산된 멤버와 상수 멤버를 섞어서 사용할 수도 있다.
하지만 계산된 멤버는
초기화되지 않은 열거형이 먼저 나오거나,
숫자 상수 또는 다른 상수 열거형 멤버와 함께 초기화된 숫자 열거형 이후여야 한다.

// EnumType.ts

const getSomeValue = () => {
  return 0;
}

export enum ExceptCase {
  A = getSomeValue(),
  B, // 오류 메시지
}

앞에 나온 A가 계산된 멤버이기 때문에 초기화가 필요하다는 오류 메시지

// EnumType.ts

const getSomeValue = () => {
  return 0;
}

export enum ExceptCase {
  A = getSomeValue(),
  B = 2, // 이후의 멤버를 초기화하면 오류 해결
}

이후의 멤버를 초기화하면 오류가 해결된다.

// EnumType.ts

const getSomeValue = () => {
  return 0;
}

export enum ExceptCase {
  A,
  B = getSomeValue(),
}

앞선 멤버가 초기화되지 않은 열거형이 먼저 나와도 가능하다.

문자열 열거형

문자열 열거형에서 각 멤버들은 문자열 리터럴 또는 다른 문자열의 멤버로 상수 초기화 해야 한다.
런타임에서 열거형 멤버에서 지정된 값을 이용하여 실행할 수 있다.
즉, 열거형은 런타임에 존재하는 실제 객체이다.
타입스크립트는 보통 타입 설정을 통해 오류를 검사하고 줄여주는 것을
주요 기능으로 알고 있으며,
컴파일을 통해 실제 실행되는 코드는
기존 코드에 영향을 주지않는 것으로 알고 있었다.

그런데 enum 열거형은 런타임에 존재하는 실제 객체이기 때문에
속성과 값을 활용할 수 있다.

// EnumType.ts

export enum E {
  X = 3,
  Y,
  Z,
}

export const func = (obj: {Y: number}) => {
  return obj.Y;
}
// App.tsx

import { func, E } from "./EnumType";

export default function App() {
  const result = func(E);

  return (
    <div className="App">
      <div>
        <span>result: </span>
        {result}
      </div>
    </div>
  );
}

E라는 enum type 내부에 Y는 실제 존재하는 객체이기 때문에
여기서 Y의 속성값인 4가 함수를 통해 전달되어 값이 나와
런타임 동작에 관여하는 실제 객체임을 확인할 수 있다.

활용

프로젝트 연습에서
enum 타입이실제 값으로 활용된 경우다.

자주 사용되는 타입이기 때문에
별도 파일로 분리하여 활용되었다.

// types.ts

export enum SelectedPage {
  Home = "home",
  Benefits = "benefits",
  OurClasses = "ourclasses",
  ContactUs = "contactus",
}

현재 페이지의 상태 관리와 활용이 필요하여
useState로 초기값을 설정해줄 때
SelectedPage enum 타입의 멤버인
Home으로 실제 존재하는 속성값("home")을 활용해주었다.

// App.tsx

import { SelectedPage } from "@/shared/types";

function App() {
  const [selectedPage, setSelectedPage] = useState<SelectedPage>(
    SelectedPage.Home
  );
  
  // (...)

  return (
    <>
      <div className="app bg-gray-20">
        <Navbar
          selectedPage={selectedPage}
          setSelectedPage={setSelectedPage}
        />
        {/* (...) */}
      </div>
    </>
  );
}

export default App;

Navbar 컴포넌트에 있는 메뉴들을 클릭하면
해당 섹션으로 스크롤이 이동하도록 구현될 것이다.

// Navbar.tsx

import { SelectedPage } from "@/shared/types";

type Props = {
  selectedPage: SelectedPage;
  setSelectedPage: (value: SelectedPage) => void;
};

const Navbar = ({ selectedPage, setSelectedPage, isTopOfPage }: Props) => {
  
  // (...)

  return (
    <nav>
      <div>
        <div>
          <div>
            {/* Left Side */}
            <img alt="logo" src={Logo} />

            {/* Right Side */}
              <div>
                <div>
                  <Link
                    page="Home"
                    selectedPage={selectedPage}
                    setSelectedPage={setSelectedPage}
                  />
                  <Link
                    page="Benefits"
                    selectedPage={selectedPage}
                    setSelectedPage={setSelectedPage}
                  />
                  <Link
                    page="Our Classes"
                    selectedPage={selectedPage}
                    setSelectedPage={setSelectedPage}
                  />
                  <Link
                    page="Contact Us"
                    selectedPage={selectedPage}
                    setSelectedPage={setSelectedPage}
                  />
                </div>
              </div>

          </div>
        </div>
      </div>
    	
    </nav>
  );
};

export default Navbar;

Link 컴포넌트에는
클릭시 해당 섹션으로 스크롤하는 로직이 들어있다.

여기서 사용되는 props 중 setlectedPage는
types.ts에서 정의해준 enum 타입이다.
앞에서 알아본 바와 같이
enum 타입의 속성값들은 컴파일 되어도 실제 존재하는 값으로
활용을 할 수 있어서,

여기서는 css 설정할 때에
prop으로 전달된 selectedPage의 속성값을
활용하여 스타일을 동적으로 설정해 줄 수 있다.

// Link.tsx

import { SelectedPage } from "@/shared/types";
import AnchorLink from "react-anchor-link-smooth-scroll";

interface Props {
  page: string;
  selectedPage: SelectedPage;
  setSelectedPage: (value: SelectedPage) => void;
}

const Link = ({ page, selectedPage, setSelectedPage }: Props) => {
  const lowerCasePage = page.toLowerCase().replace(/ /g, "") as SelectedPage;

  return (
    <AnchorLink
      className={`${
        // selectedPage 속성값을 이용하여 동적 스타일링
        selectedPage === lowerCasePage ? "text-primary-500" : ""
      } transition duration-500 hover:text-primary-300`}
      href={`#${lowerCasePage}`}
      onClick={() => setSelectedPage(lowerCasePage)}
    >
      {page}
    </AnchorLink>
  );
};

export default Link;

회고

타입스크립트 공식문서를 보면 const 열거형에 대한 설명도 있는데
이는 컴파일 과정에서 완전히 제거된다고 한다.
또한 앞서 실제 존재하는 enum 타입의 활용은
정리를 하면서 객체(object)의 모양새와 닮아 있다는 생각도 들었는데
그에 대한 설명도 있었지만, 활용을 위한 더 깊은 이해를 하기에는
시간이 좀 더 필요할 것 같다.

참고

profile
느리지만 꾸준하게. 부족하거나 잘못된 부분은 알려주시면 감사하겠습니다.

0개의 댓글