열거형(Enum), 이름공간(namespace) 만 정리를 마치면, 자바스크립트와 차별되는 타입스크립트의 문법정리는 얼추 끝나는 셈이다.
나머지는 디테일한 부분들은 “코어자바스크립트” → 자바스크립트 글에서 근본적인 자바스크립트의 구조에 대해 학습할 예정이다.
열거형
열거형으로 이름이 있는 상수들의 집합을 정의할 수 있다. 타입스크립트는 숫자와 문자열 기반 열거형을 제공한다
숫자 열거형 (Numeric enums)
enum Direction { Up = 1, Down, Left, Right,}
위 코드에서 Up 이 1로 초기화 된 숫자 열거형을 선언했는데, 그 지점부터 뒤따르는 멤버들은 자동으로 1 씩 증가된 값을 가진다.
즉 Down = 2, Left = 3, Right = 4 의 값을 가지게 된다.
따로 숫자로 초기화해주지 않으면 자동으로 0을 기준으로 1씩 증가된 값을 가지게 된다.
사용하는 방식 또한 간단하다. 열거형을 타입 선언하듯이 사용하면되는데
enum UserResponse { No = 0, Yse = 1,}// 타입 명시 하듯이 열거형을 타입 명시 자리에 적어주면 된다.function respond(recipient: string, message: UserResponse): void {...}// 열거형을 인자로 사용하기위해 UserResponse.속성 을 입력한다respond("Princess Caroline", UserResponse.Yes);
문자열 열거형 (String enums)
문자열 열거형은 숫자 열거형 처럼 자동 증가하는 기능은 없지만, “직렬화” 를 잘한다는 이점이 있다.
숫자 열거형을 사용하면 그것이 어떠한 의미를 가지는지 알기 힘든 경우가 있다 (0,1,2,3 과 같은 수일테니까, 역 매핑을 사용하면 의미있을지도..)
하지만 문자열 열거형은 반환값이 문자열이기 때문에 보다 읽기 좋은 값을 이용하여 실행할 수 있다.
enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT",}
역매핑
숫자 열거형에 있는 특징인데 reverse mapping이 가능하다.
enum Animal { Dog, Cat,}
Animal['Dog'] = 0 과 동시에 반대로 Animal[0] = 'Dog' 를 할당하는 것을 reverse mapping 이라고 한다
이종 열거형이라 해서 열거형안에서 문자열 과 숫자를 혼합해서 사용할 수도 있는데 그렇게 사용할 이유가 없다.
논란
enum은 당연히 사용하는건줄 알았더니, 인터넷에 검색을 해보니 다소 논란? 사실 논란도 아니다. 그냥 nono enum 운동을 다들 하는거 같아 놀랐다. 대충 보기에는 enum 자체가 tree shaking이 안돼서 그냥 union type 이나const enum으로 사용하거나 const object로 바꾸어서 사용한다는데 조금 더 자세하게 알아보려 한다
Enum의 문제점
TypeScript 에서 Enum을 사용하면 Tree-Shaking이 되지 않는다
Tree-shaking
Tree Shaking 은 간단히 말해 사용하지 않는 코드를 삭제하는 기능을 말한다. 나무를 흔들면 죽은 잎사귀들이 떨어지는 모습을 착안하여 Tree-shaking이라 부른다고 한다. Tree-Shaking을 통해 export했지만 아무데서도 import 하지 않은 모듈이나 코드들을 삭제하여 번들의 크기를 줄여 렌더링 시간을 줄일 수 있게 되는 것이다.
numeric enum은 타입 안정성을 보장해 주지 않는다.
enum Status { pending = 0, success = 1, fail = 2,}const newStatus: Status = 100 // 에러 발생 안함
이러한 문제점들로 인해 Enum은 사용을 지양하자는 여론이 거세다. (eslint로도 enum 사용을 막는 버전이 있다)
따라서 tree-shaking, 타입 안정성의 측면에서 enum보다 나은 방식을이 제시된다.
const enum이라고 기존 enum이 tree shaking이 되지 않는다는 단점을 극복하고자 나온 방법이다.
이 방법은 enum 코드가 컴파일시 js파일에 전부 사라지고, 전부다 인라인으로 치환되어 코드가 컴파일 된다.따라서 번들 사이즈가 줄어드는 장점이 있다. 따라서 트리 쉐이킹이 된다는 장점이 있다.
하지만 어떠한 이유로 const enum도 사용을 지양하자고 한다. const enum의 경우 컴파일시 문자열을 모두 유니코드로 변환하기 때문에 긴 문자열을 할당하는 경우 union type에 비해 다소 불리하다는 점도 있고, 호환성, 디버깅 등 의 문제를 가지고 있어서 사용을 지양양하라고 한다
As Const
이제야 정답이 나왔는데, 결국은 as const 나 union type 을 사용하라는 이야기를 길게 한것이다.
예시1
const Device = { phone: 'phone', desktop: 'desktop', tablet: 'tablet', watch: 'watch',} as const// 아래 표현이 결국 유니온타입과 동일하다 (문자열 리터럴 유니온타입)// type DeviceType = 'phone' | 'desktop' | 'tablet' | 'watch';type DeviceType = typeof Device[keyof typeof Device];
예시2
// as const로 객체 리터럴을 선언합니다.const Direction = { Up: 0, Down: 1, Left: 2, Right: 3,} as const;// 타입 정의type DirectionType = typeof Direction[keyof typeof Direction];// 함수 정의function move(direction: DirectionType) { console.log("Moving in direction:", direction);}move(Direction.Up); // Ok!move(0); // Ok!// move(100); // Error: Argument of type '100' is not assignable to parameter of type '0 | 1 | 2 | 3'.
위 두 예시와 같이 작성하면 트리 쉐이킹도 가능하고, 타입 안정성도 보장한다.
이름공간
타입스크립트의 namespace 는 코드를 구성하는 이름 충돌을 방지하고, 구조화할 수 있는 기능을 제공한다.
TypeScript의 namespace 는 모듈을 나누는데 사용될 수 있지만, 대체로 사용을 권장하지는 않는다. 대신 모듈 시스템을 사용하는 것이 좋다
현재는 ES6 모듈을 사용하는 것을 권장하고 namespace는 코드구조의 복잡성을 증가시키고, 가독성, 유지보수성을 저하시킨다.
// utils.tsexport namespace MathUtils { export function add(x: number, y: number) { return x + y; } export function subtract(x: number, y: number) { return x - y; }}// 이름공간 내부에서 export 한 요소들만 이름공간 외부에서 접근할 수 있음// 반대로 export하지 않은 요소들은 이름공간 내부에서만 접근할 수 있음console.log(MathUtils.add(10, 4));
// index.ts// 외부 파일에서 접근하기 위해서는 당연히 이름공간도 export 해줘야함import { MathUtils } from './utils';console.log(MathUtils.add(1, 2));console.log(MathUtils.subtract(1, 2));
이름공간 내부에서 export 한 요소들만 이름공간 외부에서 접근할 수 있다. 당연히 export하지 않은 요소들은 이름공간 내부에서만 접근 가능하다
그리고 이름공간을 다른공간에서 사용하기 위해서는 당연히 이름공간도 export해줘야 사용할 수 있다
당연한 얘기를 왜하냐 할 수 있는데.. 처음에 namespace 내부 요소들을 export를 해주는게 조금 헷갈려서 한번 더 짚고 넘어간다.
결론
이름공간은 다른 파일에서 중복된 이름공간이 생기면 예기치못한 에러가 발생할 수 있다.또한 이름공간의 내부 구조가 복잡해지면 가독성, 유지 보수측면에서 안좋아지므로, 현재로서는 ES6 모듈 사용을 적극 권장한다고 한다.
현재에는 이름공간은 잘 사용하지 않고, 열거형은 enum은 잘 사용하지 않고, enum을 as const나 유니온타입으로 변환하여 사용한다 정도만 알고 있으면 될듯하다