
타입스크립트의 원칙 : 런타임 기능이 아닌 타입 기능만 발전시킨다.
아래의 기능들은 이 원칙이 세워지기 전에 이미 사용되고 있어 타입 공간과 값 공간의 경계를 혼란스럽게 만들기 때문에 사용하지 않는 것이 좋다.
열거형(enum)
enum Flavor { // const enum Flavor -> 상수 열거형
VANILLA = 0,
CHOCOLATE = 1,
STRAWBERRY = 2,
}
단순히 값을 나열하는 것보다 실수가 적고 명확하기 때문에 좋지만 타입스크립트의 열거형은 상황에 따라 다르게 동작한다.
구조적 타이핑은
구조가 같으면 할당이 허용되는 반면 명목적 타이핑은타입의 이름이 같아야 할당이 허용된다
const enum Flavor {
VANILLA = 'vanilla',
CHOCOLATE = 'chocolate',
STRAWBERRY = 'strawberry',
}
let flavor = Flavor.CHOCOLATE; // 타입이 Flavor
flavor = 'strawberry';
// "strawberry' 형식은 'Flavor'형식에 할당될 수 없습니다.
function scoop(flavor: Flavor)
scoop('vanilla'); // 자바스크립트에서는 정상
scoop('vanilla'); // 타입스크립트에서는 에러 'vanilla' 형식은 'Flavor' 형식의 매개변수에 할당될 수 없습니다
자바스크립트와 타입스크립트에서 동작이 다르기때문에 문자열 열거형은 사용하지 않는 것이 좋다.
열거형 대신 리터럴 타입의 유니온을 사용하자.
type Flavor = 'vanilla' | 'chocolate' | 'strawberry';
let flavor: Flavor = 'chocolate'; //정상
function scoop(flavor: Flavor) {
if (flavor === 'v
// 자동완성이 'vanilla'를 추천합니다.
}
매개변수 속성
// 자바스크립트
class Person {
name: string;
constructor(name: string){
this.name = name;
}
}
// 타입스크립트 (매개변수 속성)
class Person {
constructor(public name: string){}
}
네임스페이스와 트리플 슬래시 임포트
namespace foo {
function bar() {}
}
/// <reference path="other.ts"/>
foo.bar
트리플 슬래시 임포트와 module 키워드는 호환성을 위해 남아있을 뿐이니 ES6 스타일의 모듈
import,export를 사용하자.
데코레이터
현재까지도 표준화가 완료되지 않았기 때문에, 앵귤러 등 애너테이션이 필요한 프레임워크를 사용 중이 아니라면 표준이 되기 전까지는 사용하지 않는 것이 좋다.
const obj= {
one: 'uno',
two: 'dos',
three: 'tres',
}
for(const k in obj) {
const v = obj[k]; // error -> k의 타입이 string
// obj에 인덱스 시그니처가 없기 때문에 엘리먼트는 암시적으로 'any' 타입입니다.
}
k의 타입은 string 이지만, obj 객체는 one,two,three 세 개의 키만 존재하기 때문에 타입이 서로 다르게 추론되어 오류가 발생한다.
오류 발생 이유?
interface ABC {
a: string;
b: string;
c: number;
}
function foo(abc: ABC){
for(const k in ABC){ // k는 string
const v = abc[k] // 'ABC" 타입에 인덱스 시그니처가 없기 때문에 엘리먼트는 암시적 'any'가 됩니다.
}
}
const x = {a: 'a', b: 'b', c: 2, d: new Date()};
foo(x)
foo 함수는 x 객체로 호출이 가능하다. ABC 타입에 할당 가능한 어떠한 값이든 매개변수로 허용하기 때문이다. (구조적 타이핑)
그렇기 때문에 타입스크립트는 ABC 타입의 키를 string 타입으로 선택한다.
k의 타입을 구체적으로 명시하기
function foo(abc: ABC) {
let k: keyof ABC;
for (k in abc) {
const v = abc[k]; // 타입이 string | number
}
}
이전 예제처럼, d 속성은 Date 타입뿐만 아니라 어떠한 타입이든 될 수 있기 때문에 v가 string | number 타입으로 추론된 것은 잘못된 것이다.
Object.entries
Object.entries를 사용하자function foo(abc: ABC) {
for(const [k, v] of Object.entries(abc)){
k // string
v // any
}
}
keyof선언은 상수이거나 추가적인 키 없이 정확한 타입을 원하는 경우,Object.entries는 더욱 일반적으로 쓰이지만 키와 값의 타입을 다루기 어렵다.
DOM 계층은 웹브라우저에서 자바스크립트를 실행할 때 어디에서나 존재한다.
타입스크립트에서는 DOM 엘리먼트의 계층 구조를 파악하기 용이하다. Element와, EventTarget에 달려 있는 Node의 구체적인 타입을 안다면 타입 오류를 디버깅 하기 쉽고 언제 타입 단얼을 사용해야 할지 알수 있다.

| 제목1 | 제목2 |
|---|---|
| EventTarget | window, XMLHttpRequest |
| Node | document, Text, Comment |
| Element | HTMLElement, SVGElement 포함 |
| HTMLElement | <i>, <b> ... |
| HTML(---)Element | <button>, <p> ... |
EventTarget
Node
Element
HTML---Element
document.getElementsByTagName('p')[0]; //HTMLParagraphElement
document.createElement('button') //HTMLButtonElement
document.querySelector('div') //HTMLDivElement | null
그러나 항상 정확한 타입을 얻을 수 있는 것은 아니다. 특히 document.getElementById에서 문제가 발생한다.
document.getElementById('my-div'); // HTMLElement
타입 단언문은 지양해야 하지만 DOM 관련해서는 타입스크립트 보다 우리가 더 정확히 알고 있는 경우이므로 단언문을 사용해도 좋다.
document.getElementById('my-div') as HTMLDivElement;
// null 체크 -> if문을 사용해도 됨
const div = document.getElementById('my-div')!;
Event 타입에도 별도의 계층 구조가 있고 각 타입마다 고유의 속성을 가지고 있다.
속성에 언더스코어(_)를 붙이는 것은 비공개라고 표시한 것뿐 클래스 외부로 공개되어 있다는 점을 주의하자!
타입스크립트 public, protected, private 접근 제어자 사용
class Foo {
_private = 'secret123';
}
class Diary {
private secret = 'cheated on my English test';
}
const diary = new Diary();
(diary as any).secret // 정상
즉, 정보를 감추기 위해 private를 사용하면 안된다.
정보를 은닉하기위해선 클로저를 사용해야 한다.
declare function hash(text: string): number;
class Passwordchecker {
checkPassword: (password: string) => boolean;
constructor(passwordHash: number) {
this.checkPassword = (password: string) => {
return hash(password) === passwordHash;
}
}
}
const checker = new PasswordChecker(hash('s3cret'));
checker.checkPassword('s3cret'); // 결과는 true
현재 표준화 진행중인 정보 은닉 방법
비공개 필드 기능은 접두사로 #을 붙여 타입 체크와 런타임 모두에서 비공개로 만드는 역할을 한다.
class Passwordchecker {
#passwordHash: number;
constructor(passwordHash: number) {
this.#passwordHash = passwordHash;
}
checkPassword(password: string) {
return hash(password) === this.#passwordHash;
}
}
const checker = new Passwordchecker(hash('s3cret1'));
checker.checkPassword('secret'); // 결과는 false
checker.checkPassword('s3cret'); // 결과는 true
#passwordHash 속성은 클래스 외부에서 접근할 수 없으며, 클로저와 다르게 클래스 메서드나 동일한 클래스의 개별 인스턴스끼리는 접근이 가능하다.
클로저를 사용하자.타입스크립트 코드를 실행한다는 것은, 엄밀히 말하자면 타입스크립트 컴파일러가 생성한 자바스크립트 코드를 실행한다는 것이다.
변환된 자바스크립트코드는 복잡해서 디버깅하기 어렵다. -> 이를 해결하기위해 Source Map 이 만들어졌다.
// tsconfig.json
{
"compilerOptions": {
"sourceMap": true
}
}
이제 컴파일을 실행하면 각 .ts 파일에 대해 .js와 .js.map 두 개의 파일을 생성한다. .js.map 파일이 소스맵이다.
Source Map
타입 체커가 디버거를 대체할 수는 없다. 소스맵을 사용해서 제대로 된 타입스크립트 디버깅 환경을 구축하자!