타입스크립트 초창기 시절에 도입된 몇 가지 기능을 사용하면, 타입 공간(타입스크립트) 값 공간(자바스크립트)의 경계를 혼란스럽게 한다고 합니다. 이에 대해서 알아봅시다.
1. 타입스크립트 의 열거형(enum)과 관련된 문제
타입스크립트 열거형은 상황에 따라 다르게 동작한다고 합니다. 아래 예제를 통해 확인할 수 있습니다.
|
enum Flavor {
VANILLA = 0,
CHOCOLATE = 1,
STRAWBERRY = 2,
}
let flavor = Flavor.CHOCOLATE; // 타입이 Flavor
let flavor2 = Flavor[0] // 값이 "VANILLA"; 타입은 string
|
a. Flavor 타입에 0, 1, 2 외 다른 숫자가 할당되면 매우 위험합니다.
|
let flavor3 = Flavor[4] // 매우 위험함.
|
b. 상수 열거형은 보통의 열거형과 달리 런타임에 완전히 제거됩니다.
|
const enum Flavor {
VANILLA = 0,
CHOCOLATE = 1,
STRAWBERRY = 2,
}
|
위 예제는 컴파일 완료되면 완전히 사라집니다. const를 제거하면 컴파일시 코드가 생성됩니다.
c. 문자열 열거형은 런타임의 타입 안정성과 투명성을 제공합니다. 그라나 타입스크립트의 다른 타입과 달리 구조적 타이핑이 아닌 명목적 타이핑을 사용합니다.
|
const enum Flavor {
VANILLA = 'vanilla',
CHOCOLATE = 'chocolate',
STRAWBERRY = 'strawberry',
}
let flavor = Flavor.CHOCOLATE; // 타입이 Flavor
flavor = 'strawberry'; // 오류. 구조적 타이핑이 통하지 않음.
|
위 예제에서 Flavor는 런타임 시점에서는 문자열로서 동작합니다. 반면, 타입스크립트에서는 열거형 타입과 문자열 타입 간 구조적 타이핑이 되지 않기 때문에 혼란스럽습니다.
따라서 열거형 보다는 리터럴 타입의 유니온을 사용하는 것이 더 낫습니다.
|
type FlavorFix = 'vanilla' | 'chocolate' | 'strawberry';
|
2. 매개변수 속성과 관련된 문제(?)
일반적으로 클래스를 초기화할 때 속성을 할당하기 위해 생성자의 매개변수를 활용합니다.
|
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
}
|
위와 같은 예제를 좀더 간단히 구현할 수 있도록 타입스크립트에서는 '매개변수 속성' 기능을 지원합니다. 아래 예제는 위의 예제와 완전히 동일하게 동작합니다.
|
class PersonFix{
constructor(public name: string) {}
}
|
위 예제의 생성자 파라미터의 'public name'은 '매개변수 속성'이라고 합니다.
'매개변수 속성' 에는 몇가지 문제가 있다고 합니다.
* 매개변수 속성은 컴파일시 코드가 늘어나는 문법입니다.
* 매개변수 속성이 런타임에는 실제로 사용되지만, 타입스크립트 관점에서는 사용되지 않는 것처럼 보입니다.
* 매개변수 속성과 일반 속성을 섞어서 사용하면 클래스의 설계가 혼란스럽습니다.
|
class Person{
first: string;
last: string;
constructor(public name: string) {
[this.first, this.last] = name.split(' ');
}
}
|
위 예제를 보면 실제로 클래스에는 3개의 속성이 있지만 first, last 속성만 명시적으로 나열되고 있어 일관성이 없어 보입니다.
저자는 '매개변수 속성' 사용엔 호불호가 많이 갈리는 기능이라고 합니다.
3. 네임스페이스 트리플 슬래시 임포트
타입스크립트에서 모듈 내보내기 및 가져오기 기능을 사용할 때 'import'와 'export'를 이용하라는 내용입니다.
4. 데코레이터
데코레이터는 클래스, 메서드, 속성에 annotation을 추가하거나 기능을 추가하는 데 사용할 수 있습니다. 예를 들어, 클래스의 매서드가 호출될 때마다 로그를 남기려면 logged annotation 정의할 수 있습니다.
|
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@logged
greet() {
return "Hello, " + this.greeting;
}
}
function logged(target: any, name: string, descriptor: PropertyDecorator) {
const fn = target[name];
descriptor.value = function () {
console.log(`Calling ${name}`);
return fn.apply(this, arguments);
};
}
console.log(new Greeter('Dave').greet());
// [LOG]: "Calling greet"
// [LOG]: "Hello, Dave"
|
데코레이터는 처음에 앵귤러 프레임워크를 지원하기 위해 추가되었습니다. tsconfig.json의 experimentalDecorators 속성을 enable 해야 사용 가능한 기능입니다. 아직 표준화가 완료되지 않은 기능입니다. 따라서 아직 까진 데코레이터를 사용하지 않는 편이 좋습니다. (앵귤러 등 annotation 기능이 필요한 프레임웍을 사용하려면 데코레이터 사용할 수 있지만..)
'IT' 카테고리의 다른 글
| Effective Typescript - 56 - 정보를 감추는 목적으로 private 사용하지 않기 (0) | 2022.01.24 |
|---|---|
| Effective Typescript - 54 - 객체를 순회하는 노하우 (1) | 2022.01.24 |
| Effective Typescript - 52 - 테스팅 타입의 함정에 주의하기 (0) | 2022.01.24 |
| Effective Typescript - 51 - 의존성 분리를 위해 미러 타입 사용하기 (0) | 2022.01.24 |
| Effective Typescript - 50 - 오버로딩 타입보다는 조건부 타입을 사용하기 (0) | 2022.01.24 |