-
TypeScript | Enum 열거형 타입JavaScript/TypeScript 2020. 5. 6. 15:13
Enum 열거형 타입
열거형 타입은 enum 키워드를 사용해서 정의
열거형 타입의 각 원소는 값 또는 타입으로 사용 가능// 열거형 타입으로 과일 정의 enum Fruit { Apple, Banana, Orange } // 열거형 타입의 원소인 Apple을 값으로 사용 const v1: Fruit = Fruit.Apple; // 열거형 타입의 원소인 Apple, Banana를 타입으로 사용 const v2: Fruit.Apple | Fruit.Banana = Fruit.Banana;
enum 원소의 값
enum Fruit { Apple, Banana = 5, Orange } console.log(Fruit.Apple, Fruit.Banana, Fruit.Orange); // 0 5 6
- 열거형 타입의 첫 번째 원소에 값을 할당하지 않으면 자동으로 0 할당
- 열거형 타입의 각 원소에 숫자 또는 문자열 할당 가능
명시적으로 값을 입력하지 않으면 이전 원소에서 1만큼 증가한 값 할당
객체로 존재하는 열거형 타입
// 타입스크립트는 위의 코드를 아래와 같이 컴파일 var Fruit; (function(Fruit){ Fruit[(Fruit['Apple'] = 0)] = 'Apple'; Fruit[(Fruit['Banana'] = 5)] = 'Banana'; Fruit[(Fruit['Orange'] = 6)] = 'Orange'; })(Fruit || (Fruit = {})); console.log(Fruit.Apple, Fruit.Banana, Fruit.Orange); // 0, 5, 6
- 열거형 타입은 객체로 존재
- 열거형 타입의 각 원소는 이름과 값이 양방향으로 매핑(mapping)
- 열거형 타입은 객체로 존재하기 때문에 해당 객체를 런타임에 사용 가능
열거형 타입 객체 사용하기
enum Fruit { Apple, Banana = 5, Orange } console.log(Fruit.Banana); // 5 console.log(Fruit['Banana']); // 5 console.log(Fruit[5]); // Banana
- 열거형 타입은 객체이기 때문에 일반적인 객체처럼 다룰 수 있음
- 각 원소의 이름과 값이 양방향으로 매핑되어 있기 때문에 값을 이용해서 이름을 가져올 수 있음
→ 단, 서로 다른 원소에 같은 수를 할당하는 경우 마지막 원소의 이름을 반환
열거형 타입의 값으로 문자열 할당
enum Language { Korean = 'ko', English = 'en', Japanese = 'jp' } console.log(Language.Korean); // ko console.log(Language['ko']); // 에러 발생 // 컴파일 결과 "use strict"; var Language; (function (Language) { Language["Korean"] = "ko"; Language["English"] = "en"; Language["Japanese"] = "jp"; })(Language || (Language = {}));
- 열거형 타입의 원소에 문자열을 할당하는 경우 단방향으로 매핑됨
- 이는 서로 다른 원소의 이름 또는 값이 같을 경우 충돌이 발생하기 때문
→ 컴파일 결과를 보면 위에서 봤던 컴파일 결과와 매핑 형식이 다름을 알 수 있음
열거형 타입을 위한 유틸리티 함수
열거형 타입을 자주 사용한다면 몇 가지 유틸리티 함수를 만들어서 사용하는 것이 좋음
열거형 타입의 원소 개수를 알려 주는 함수
function getEnumLength(enumObject: any) { const keys = Object.keys(enumObject); return keys.reduce( // enum 원소의 값이 숫자이면 2씩 증가하므로 문자열만 계산 (acc, key) => (typeof enumObject[key] === 'string' ? acc + 1 : acc), 0 ) }
- 원소의 값이 숫자인 경우에는 양방향으로 매핑되기 때문에 주의해야 함
- 객체의 속성값이 문자열인 경우만 계산하면 열거형 타입에서 원소의 개수를 구할 수 있음
열거형 타입에 존재하는 값인지 검사하는 함수
function isValidEnumValue(enumObject: any, value: number | string) { if(typeof value === 'number'){ return !!enumObject[value]; } else { return ( Object.keys(enumObject) .filter(key => isNaN(Number(key))) .find(key => enumObject[key] === value) != null ) } }
- 찾으려는 값이 숫자이면 양방향 매핑을 이용해서 검사
!! → 값이 있는 경우 true를 반환하기 위함 - 찾으려는 값이 문자열이면 양방향 매핑에 의해 생성된 키를 제거하고 해당 값이 존재하는지 검사
- find 메서드에서 !=(엄격하지 않은 비교)를 사용하는 이유는 undefined를 가려내기 위함
undefined !== null은 true를 반환
간단한 사용 예제
enum Fruit { Apple, Banana, Orange } enum Language { Korean = 'ko', English = 'en', Japanese = 'jp' } console.log(getEnumLength(Fruit), getEnumLength(Language)); // 3 3 console.log('1 in Fruit', isValidEnumValue(Fruit, 1)); // true console.log('5 in Fruit', isValidEnumValue(Fruit, 5)); // false console.log('ko in Language', isValidEnumValue(Language, 'ko')); // true console.log('Korean in Language', isValidEnumValue(Language, 'Korean')); // false
실용적 활용 예제
isValidEnum 함수는 서버로부터 받은 데이터를 검증할 때 사용 가능
getEnumLength 함수는 다음과 같이 실수 방지 용도로 사용 가능
enum Fruit { Apple, Banana, Orange } // 과일의 가격 정보를 가진 객체 const FRUIT_PRICE = { [Fruit.Apple]: 1000, [Fruit.Banana]: 1500, [Fruit.Orange]: 2000 } // 이하 코드는 jest와 같은 테스팅 프레임 워크 필요 test('FRUIT_PRICE에 정의되지 않은 Fruit가 있는지 체크' () => { expect(getEnumLength(Fruit)).toBe(Object.keys(FRUIT_PRICE).length); });
- 과일 가격 정보 객체는 Fruit의 모든 원소를 갖고 있어야 함
- 따라서 Fruit에 새로운 과일이 추가되면 FRUIT_PRICE에도 반드시 해당 과일의 가격을 추가해야 함
- getEnumLength 함수를 이용해서 테스트 코드를 작성하면 Fruit와 FRUIT_PRICE의 크기를 항상 같게 유지할 수 있음
상수 열거형 타입
열거형 타입은 컴파일 후에도 남아 있기 때문에 번들 파일의 크기가 불필요하게 커질 수 있음
상수(const) 열거형 타입을 사용하면 컴파일 결과에 열거형 타입의 객체를 남겨 놓지 않을 수 있음const enum Fruit { Apple, Banana, Orange, } const fruit: Fruit = Fruit.Apple; const enum Language { Korean = 'ko', English = 'en', Japanese = 'jp', } const lang: Language = Language.Korean; console.log(getEnumLength(Fruit)); // 컴파일 에러 발생 // 컴파일 결과 "use strict"; const fruit = 0 /* Apple */; const lang = "ko" /* Korean */;
- 컴파일 결과에 열거형 타입의 객체를 생성하는 코드가 보이지 않음
- 열거형 타입이 사용된 코드는 원소의 값으로 대체되므로 코드가 간소화됨
- 하지만 상수 열거형 타입을 사용하면 열거형 타입 객체 사용 불가
참고도서: [실전 리액트 프로그래밍 / 저자_ 이재승 / 출판사_ 프로그래밍 인사이트]
'JavaScript > TypeScript' 카테고리의 다른 글
TypeScript | 타입 호환성 (0) 2020.05.07 TypeScript | Interface 인터페이스 (0) 2020.05.07 TypeScript | 함수형 타입 (0) 2020.05.06 TypeScript | 개요 & 변수 타입 (0) 2020.05.06