타입스크립트 소개
- 1.1 타입스크립트와 자바스크립트의 관계
- 1.2 타입스크립트 설정 이해하기
- 1.3 코드 생성과 타입이 관계없음을 이해하기
- 1.4 구조적 타이핑에 익숙해지기
- 1.5 any 타입 지양하기
타입스크립트를 제대로 쓰려면, 먼저 이게 뭔지부터 정확히 알아야 해. 그냥 "자바스크립트에 타입 붙인 거"라고 넘어가면 나중에 반드시 헷갈리는 순간이 온다.
타입스크립트는 자바스크립트의 상위집합(superset) 이야. 모든 자바스크립트 프로그램은 이미 타입스크립트 프로그램이거든. .js 파일 확장자를 .ts로 바꿔도 동작해. 반대는 안 돼 — 타입스크립트에는 타입 구문이 있으니까 JS 파서가 이해를 못 하지. 이 관계가 중요한 이유는, TS로 마이그레이션할 때 기존 JS 코드를 한 줄도 안 바꾸고 시작할 수 있다는 뜻이기 때문이야. 점진적 도입이 가능한 이유가 바로 여기 있어. 다만 "상위집합"이라고 해서 TS가 JS의 런타임 동작을 바꾸는 건 아니야. TS의 타입 시스템은 정적 분석 도구일 뿐이고, 실행 시점에는 모든 타입 정보가 사라져. 타입 체커가 오류를 잡아준다고 해서 모든 오류를 잡는 것도 아니고 — 런타임에서만 발견되는 로직 오류는 여전히 테스트로 잡아야 해.
TS 컴파일러 설정 중에서 저자가 강조하는 핵심 설정은 두 가지야. **noImplicitAny**는 타입을 명시하지 않은 변수에 암묵적으로 any가 붙는 걸 막아주고, **strictNullChecks**는 null과 undefined가 모든 타입에 대입 가능한지를 제어해. strictNullChecks를 끄면 모든 타입에 null이 슬쩍 들어갈 수 있어서 런타임에 "Cannot read property of null" 에러가 터지거든. 저자의 조언은 단호해 — 새 프로젝트라면 무조건 strict: true로 시작하라. 기존 프로젝트를 마이그레이션하는 경우라면 noImplicitAny부터 켜고, 그다음 strictNullChecks를 켜는 식으로 점진적으로 가는 게 현실적이야. TS 설정이 다른 상태에서 같은 코드를 보면 완전히 다른 의미가 되기 때문에, 누군가의 TS 코드를 볼 때는 항상 tsconfig.json부터 확인해야 해.
TS를 처음 쓰는 사람들이 가장 많이 헷갈리는 부분이 있어. TS 컴파일러(tsc)가 하는 일은 크게 두 가지인데 — TS/JS를 구버전 JS로 트랜스파일하는 것과, 코드의 타입 오류를 체크하는 것. 이 두 가지는 완전히 독립적이야. 타입 오류가 있어도 JS 코드는 생성돼. 많은 사람이 "컴파일 에러"라고 말하지만, 정확히는 "타입 체크 에러"지. 컴파일(트랜스파일)은 잘 돼. 런타임에 타입 체크를 할 수도 없어 — interface나 type은 컴파일 결과물에 아예 존재하지 않거든. 런타임에 타입을 분기하고 싶으면 태그드 유니온(tagged union)이나 클래스를 써야 해. as number 같은 타입 단언이 실제로 값을 변환하지도 않아. 진짜로 값을 바꾸고 싶으면 Number() 같은 런타임 함수를 써야 하고. 대신 타입은 빌드 타임에만 존재하니까 런타임 오버헤드는 전혀 없어.
자바나 C# 같은 언어는 **명목적 타이핑(nominal typing)**을 써. 같은 구조를 가져도 이름이 다르면 다른 타입이지. 타입스크립트는 **구조적 타이핑(structural typing)**을 쓰거든. 구조가 같으면 이름이 달라도 호환 가능한 타입으로 취급해.
interface Vector2D {
x: number;
y: number;
}
interface NamedVector {
name: string;
x: number;
y: number;
}
NamedVector는 Vector2D에 name이 추가된 것뿐이니까, Vector2D를 받는 함수에 NamedVector를 넘겨도 돼. 이게 덕 타이핑(duck typing)이랑 비슷한 개념이야 — "오리처럼 걷고, 오리처럼 꽥꽥대면, 오리다." 구조적 타이핑의 장점은 유연성이야. 인터페이스를 명시적으로 implements 안 해도 호환되니까 테스트 시 모킹이 쉽지. 단점은 의도치 않은 타입 호환이 생길 수 있다는 건데, 이건 7장의 브랜딩 기법으로 해결할 수 있어.
마지막으로 any 얘기를 안 할 수가 없어. any는 TS의 비상구야. 타입 체크를 완전히 끄는 것과 같거든. any를 쓰면 숫자에 문자열 메서드를 호출해도 컴파일러가 아무 말 안 하고, 함수 시그니처를 무시하고, 자동완성도 안 되고, 리팩터링할 때 컴파일러가 잡아주지도 않아. 타입 시스템 전체의 신뢰를 떨어뜨리는 거지. any는 TS에서 JS로 돌아가는 것과 같아. TS를 쓰는 이유가 타입 안전성이라면, any를 쓰는 순간 그 이유가 사라져. 불가피하게 써야 하는 상황이라면 5장에서 다루는 좁은 스코프 기법이나 unknown을 활용해야 해.
정리
1장 읽고 기억할 거 세 가지:
- TS는 JS의 상위집합이고, 타입은 컴파일 타임에만 존재한다. 런타임에는 타입 정보가 전부 사라진다. 코드 생성과 타입 체크는 독립적인 작업.
- 구조적 타이핑이 TS의 핵심 특성이다. 이름이 아니라 구조로 타입 호환성을 판단한다. 유연하지만 의도치 않은 호환에 주의.
any는 타입 시스템의 비상구이자 독약이다. 가능한 한 피하고, 꼭 써야 하면 스코프를 최소화해라.