January 15, 2022 • ☕️ 7 min read
코드를 작성하고 실행하기
자바스크립트에 새로 추가된 기능은 타입스크립트의 초기 기능과 호환성 문제를 발생시켰다
열거형(enum
)
몇몇 값의 모음을 나타내는 방식
😵 문제점
const enum
)은 런타임에 완전히 제거되어, 문자열 열거형에서 문제를 일으킨다preserveConstEnums
플래그를 설정한 상수 열거형은 런타임 코드에 정보를 유지한다문자열 열거형의 명목적 타이핑은 자바스크립트와 동작이 다르다는 문제가 있다
enum Flavor {
VANILLA = "vanilla",
CHOCOLATE = "chocolate",
STRAWBERRY = "strawberry",
}
let flavor = Flavor.CHOCOLATE; // 타입이 Flavor
flavor = "strawberry"; // 🚨 'strawberry' 형식은 'Flavor' 형식에 할당할 수 없습니다
→ 열거형 대신 리터럴 타입의 유니온 사용을 권장한다
type Flavor = "vanilla" | "chocolate" | "strawberry";
매개변수 속성
생성자의 매개변수를 사용하여 클래스 초기화 시 타입스크립트에는 간결한 문법을 제공한다
class Person {
constructor(public name: string) {}
}
😵 문제점
네임스페이스와 트리플 슬래시 임포트
namespace foo {
function bar() {}
}
/// <reference path="other.ts" />
foo.bar();
→ ES2015 스타일의 모듈(import
와 export
) 사용을 권장한다
데코레이터
편집기에서 오류가 발생하는 경우
const obj = {
one: "uno",
two: "dos",
three: "tres",
};
for (const k in obj) {
const v = obj[k];
// 🚨 obj에 인덱스 시그니처가 없기 때문에 엘리먼트는 암시적으로 'any' 타입입니다
}
→ k
가 string
으로 인식되기 때문이다
k
의 타입을 더욱 구체적으로 명시해서 해결한다
let k: keyof typeof obj;
for (k in obj) {
const v = obj[k]; // 정상
}
🤔 k
가 string
으로 추론된 이유
interface ABC {
a: string;
b: string;
c: number;
}
function foo(abc: ABC) {
for (const k in abc) {
const v = abc[k]; // 🚨
}
}
a
, b
, c
외에 다른 속성이 존재하는 객체도 foo
함수의 매개변수 abc
에 할당 가능하기 때문이다keyof
을 사용하는 것의 문제
v
도 string | number
로 한정되어 범위가 너무 좁아진다단지 객체의 키와 값을 순회하고 싶다면 Object.entries
를 사용한다
function foo(abc: ABC) {
for (const [k, v] of Object.entries(abc)) {
k; // string 타입
v; // any 타입
}
}
타입 | 예시 |
---|---|
EventTarget | window, XMLTHttpRequest |
Node | document, Text, Comment |
Element | HTMLElement, SVGElement 포함 |
HTMLElement | <i> , <b> |
HTMLButtonElement | <button> |
EventTarget
DOM 타입 중 가장 추상화된 타입으로, 이벤트리스너의 추가/제거, 이벤트 보내기만 가능
function handleDrag(eDown: Event) {
const targetEl = eDown.currentTarget;
targetEl.classList.add('dragging');
// 🚨 개체가 null인 것 같습니다.
// 🚨 'EventTarget' 형식에 'classList' 속성이 없습니다
Event
의 currentTarget
속성의 타입은 EventTarget | null
Node
Element
가 아닌 Node
Element
와 HTMLElement
SVGSvgElement
HTMLxxxElement
HTMLxxxElement
형태의 특정 엘리먼트들은 자신만의 고유한 속성을 가지고 있다
HTMLImageElement
- src
, HTMLInputElement
- value
항상 정확한 타입을 얻을 수 있는 것은 아니다
// 정확한 타입
document.createElement("button"); // HTMLButtonElement
// 정확한 타입이 아닌 경우
document.getElementById("my-div"); // HTMLElement
타입 단언문 사용
document.getElementById("my-div") as HTMLDivElement;
strictNullChecks
설정 시 엘리먼트가 null
인 경우를 체크한다
Event
는 가장 추상화된 이벤트로, 별도의 계층구조를 가진다
UIEvent
, MouseEvent
, TouchEvent
, WheelEvent
, KeyboardEvent
public
, protected
, private
같은 접근 제어자
심지어 단언문을 사용하면 타입스크립트 상태에서도 private
속성에 접근 가능하다
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
PasswordChecker
의 생성자 외부에서 passwordHash
변수에 접근할 수 없기 때문에 정보가 숨겨진다
passwordHash
에 접근하는 메서드 역시 생성자 내부에 정의되어야 한다비공개 필드 (현재 표준화 진행중) 사용하기
#
디버거는 런타임에 동작하며, 현재 동작하는 코드가 어떤 과정을 거쳤는지 모른다
디버깅 문제를 해결하기 위해 브라우저는 소스맵(source map) 기능을 제공한다
타입스크립트의 소스맵 활성화
// tsconfig.json
{
"compilerOptions": {
"sourceMap": true
}
}
→ 각 .ts
파일에 대해서 .js
와 .js.map
두 개의 파일을 생성한다
소스맵에 대해 알아야 할 사항들