아이템 1 타입스크립트와 자바스크립트 관계 이해하기
타입스크립트는 다른 언어들과 다르게 저수준 언어로 컴파일되지 않습니다. 또 다른 고수준 언어인 자바스크립트로 컴파일되고, 실행됩니다. 타입스크립트가 자바스크립트로 컴파일되고 실행 역시 자바스크립트로 되는 이유는 자바스크립트의 장점을 활용하기 위함입니다. 자바스크립트의 표준성, 호환성, 유연성, 다양한 환경 지원, 그리고 풍부한 생태계를 활용할 수 있기 때문이라고 생각됩니다.
타입시스템의 목표 중 하나는 런타임에 오류를 발생시킬 코드를 미리 찾아내는 것. 명시적으로 타입을 선언하여 의도를 분명히 하게 되면 오류가 어디서 발생했는지 알 수 있고 올바른 해결책을 받을 수 있습니다.
const student = [
{name: 'hoho', address: 'busan'},
{name: 'haha', address: 'seoul'},
{name: 'hehe', address: 'ny'},
];
보다는
interface Student = {
name: string;
address: string;
}
const students: Student[] = [
{name: 'hoho', address: 'busan'},
{name: 'haha', address: 'seoul'},
{name: 'hehe', address: 'ny'},
];
의도를 명확히 해서 타입스크립트가 잠재적 문제점을 찾을 수 있게 합니다.
아이템 2 타입스크립트 설정 이해하기
타입스크립트에서 설정을 사용하면 타입스크립트를 어떻게 사용할 계획인지 동료들과 다른 도구들이 알 수 있습니다.
타입스크립트의 설정 중 `noImplicitAny`와 `strictNullChecks` 옵션은 타입 안전성을 강화하는 중요한 역할을 합니다.
noImplicitAny
`noImplicitAny` 옵션은 암시적인 `any` 타입 사용을 방지한다. 이 옵션을 활성화하면, 타입스크립트는 명시적으로 타입을 지정하지 않은 경우 암시적으로 `any` 타입을 할당하지 않고 오류를 발생시킵니다.
'작동 방식'
타입스크립트에서 타입을 명시하지 않으면 컴파일러는 해당 변수나 매개변수에 `any` 타입을 암시적으로 할당합니다. 이는 타입 안전성을 저해할 수 있습니다. `noImplicitAny` 옵션을 활성화하면, 타입스크립트는 타입을 명시적으로 지정하지 않은 경우 컴파일러 오류를 발생시켜 타입 명시를 강제합니다.
function add(a, b) {
return a + b;
}
noImplicitAny가 true인 경우, 위 함수는 오류를 발생시킵니다.
!! 오류: 매개변수 'a'와 'b'의 타입을 암시적으로 'any'로 할 수 없습니다.
function add(a: number, b: number): number {
return a + b;
}
위와 같이 타입을 명시하면 오류가 해결됩니다.
strictNullChecks
`strictNullChecks` 옵션은 `null`과 `undefined`가 다른 모든 타입과 호환되지 않도록 합니다. 이 옵션을 활성화하면, `null` 또는 `undefined` 값을 할당하거나 반환할 수 있는 변수나 매개변수는 명시적으로 그 타입에 `null` 또는 `undefined`를 포함해야 합니다.
'작동 방식'
기본적으로, 타입스크립트는 모든 타입에 `null`과 `undefined`를 할당할 수 있습니다. 이는 런타임 에러를 유발할 수 있습니다. `strictNullChecks` 옵션을 활성화하면, `null`과 `undefined`가 각기 다른 타입으로 취급되며, 이를 처리하기 위해 코드에서 명시적으로 해당 타입을 포함하거나 검사해야 합니다.
let name: string = "Alice";
name = null; // strictNullChecks가 false인 경우 허용됩니다.
name = undefined; // strictNullChecks가 false인 경우 허용됩니다.
let name: string | null = "Alice";
name = null; // strictNullChecks가 true인 경우, 이렇게 명시적으로 타입에 null을 포함해야 합니다.
function greet(name: string | undefined) {
console.log("Hello, " + name);
}
// strictNullChecks가 true인 경우, 매개변수에 undefined를 명시적으로 포함해야 합니다.
요약
- noImplicitAny: 암시적인 `any` 타입 사용을 방지하여 타입 안전성을 높입니다. 타입을 명시적으로 지정하지 않으면 컴파일 오류를 발생시킵니다.
- strictNullChecks: `null`과 `undefined`가 다른 타입과 호환되지 않도록 하여 런타임 오류를 줄입니다. `null` 또는 `undefined`를 처리하려면 명시적으로 해당 타입을 포함하거나 검사해야 합니다.
이 두 옵션을 활성화하면 코드의 타입 안전성을 크게 강화할 수 있으며, 런타임 에러를 예방하는 데 도움이 됩니다.
아이템 3 코드 생성과 타입이 관계없음을 이해하기
타입스크립트의 타입 시스템이 런타임 성능에 영향을 주지 않는다는 점은 매우 중요한 특성입니다. 이를 이해하기 위해 몇 가지 중요한 사항을 설명하겠습니다.
'타입스크립트의 타입 시스템과 런타임'
1. 컴파일 타임 타입 검사
타입스크립트는 정적 타입 언어로, 타입 검사는 컴파일 시점에 이루어집니다. 타입스크립트 컴파일러는 코드를 분석하여 타입 오류를 찾아내고, 이러한 오류가 있을 경우 컴파일 단계에서 개발자에게 경고를 제공합니다. 따라서 타입스크립트의 타입 시스템은 코드가 실제로 실행되기 전에 오류를 잡아낼 수 있습니다.
2. 런타임 코드
타입스크립트 코드는 컴파일 시점에 자바스크립트 코드로 변환됩니다. 변환된 자바스크립트 코드는 타입 정보가 제거된 상태로, 순수한 자바스크립트 코드만이 남게 됩니다. 따라서 런타임 시에는 타입스크립트의 타입 시스템이 전혀 관여하지 않습니다. 이는 타입스크립트가 자바스크립트의 상위 집합이라는 특성 덕분입니다.
타입스크립트의 성능 무영향성
타입스크립트의 타입 시스템이 런타임 성능에 영향을 주지 않는 이유는 다음과 같습니다:
1. 타입 제거
타입스크립트 컴파일러(tsc)가 타입스크립트 코드를 자바스크립트 코드로 변환할 때 모든 타입 정보는 제거됩니다. 즉, 최종적으로 생성된 자바스크립트 코드에는 타입 정보가 포함되지 않으며, 자바스크립트 엔진은 타입 정보를 처리할 필요가 없습니다.
2. 동일한 런타임 환경
변환된 자바스크립트 코드는 일반 자바스크립트 코드와 동일하게 실행됩니다. 따라서 타입스크립트로 작성된 코드도 동일한 런타임 성능을 제공합니다. 자바스크립트 엔진(V8, SpiderMonkey 등)은 타입스크립트 코드가 아닌 자바스크립트 코드를 실행하기 때문에, 타입스크립트의 타입 시스템은 런타임 성능에 영향을 미치지 않습니다.
다음은 타입스크립트 코드와 변환된 자바스크립트 코드의 예시입니다:
// TypeScript 코드
function add(a: number, b: number): number {
return a + b;
}
위의 타입스크립트 코드는 다음과 같이 자바스크립트로 변환됩니다:
// Transpiled JavaScript 코드
function add(a, b) {
return a + b;
}
타입스크립트의 타입 정보는 컴파일 시점에만 사용되고, 최종 자바스크립트 코드에는 포함되지 않습니다. 이는 런타임 성능에 아무런 영향을 주지 않습니다.
결론
타입스크립트의 타입 시스템은 컴파일 타임에만 작동하며, 런타임 성능에 영향을 미치지 않는다는 점은 개발자에게 큰 장점입니다. 이를 통해 타입 안전성을 유지하면서도 자바스크립트의 런타임 성능을 그대로 활용할 수 있습니다.
아이템 4 구조적 타이핑에 익숙해지기
'자바스크립트가 덕 타이핑 기반이고 타입스크립트가 이를 모델링하기 위해 구조적 타이핑을 사용함을 이해해야 한다.'
위 문장은 자바스크립트와 타입스크립트의 타입 시스템 간의 관계를 설명하고 있습니다. 이를 쉽게 이해하기 위해 다음과 같은 방식으로 풀어보겠습니다.
자바스크립트와 덕 타이핑
자바스크립트는 덕 타이핑(Duck Typing) 개념을 기반으로 합니다. 이는 다음과 같은 의미를 가집니다:
- 덕 타이핑: 객체의 실제 타입보다는 객체가 가진 속성과 메서드에 따라 그 객체의 타입을 결정합니다. 즉, 객체가 필요한 속성과 메서드를 가지고 있다면, 그 객체는 적절한 타입으로 간주될 수 있습니다.
- 예시: 만약 어떤 객체가 `quack`이라는 메서드를 가지고 있다면, 그 객체는 '오리'처럼 취급될 수 있습니다.
let duck = {
quack: function() {
console.log("Quack!");
}
};
let person = {
quack: function() {
console.log("I'm quacking like a duck!");
}
};
function makeItQuack(thing) {
thing.quack();
}
makeItQuack(duck); // Quack!
makeItQuack(person); // I'm quacking like a duck!
위의 예시에서 `duck`과 `person` 객체는 모두 `quack` 메서드를 가지고 있기 때문에, `makeItQuack` 함수는 두 객체 모두를 받아들일 수 있습니다. 자바스크립트는 이처럼 객체의 구조(속성과 메서드)에 기반하여 타입을 결정합니다.
타입스크립트와 구조적 타이핑
타입스크립트는 자바스크립트의 덕 타이핑을 모델링하기 위해 구조적 타이핑(Structural Typing) 방식을 사용합니다. 구조적 타이핑은 객체의 구조(속성과 메서드)에 따라 타입을 결정합니다. 이는 자바스크립트의 덕 타이핑과 매우 유사하지만, 타입스크립트는 정적 타입 검사를 통해 이를 강화합니다.
- 구조적 타이핑 객체의 타입은 그 객체의 구조에 의해 결정됩니다. 객체가 필요한 속성과 메서드를 모두 가지고 있으면, 그 객체는 해당 타입으로 간주됩니다.
- 타입 검사: 타입스크립트는 컴파일 타임에 타입 검사를 수행하여 코드의 타입 안전성을 높입니다.
interface Quackable {
quack(): void;
}
let duck: Quackable = {
quack: function() {
console.log("Quack!");
}
};
let person: Quackable = {
quack: function() {
console.log("I'm quacking like a duck!");
}
};
function makeItQuack(thing: Quackable) {
thing.quack();
}
makeItQuack(duck); // Quack!
makeItQuack(person); // I'm quacking like a duck!
위의 타입스크립트 예시에서 `Quackable` 인터페이스는 `quack` 메서드를 정의하고 있으며, `duck`과 `person` 객체는 이 인터페이스를 구현하고 있습니다. `makeItQuack` 함수는 `Quackable` 타입을 요구하며, `duck`과 `person` 객체는 해당 타입에 맞기 때문에 함수 호출이 가능합니다.
요약
- 자바스크립트가 덕 타이핑 기반이다: 자바스크립트에서는 객체의 실제 타입보다는 객체가 가진 속성과 메서드에 따라 타입을 결정합니다.
- 타입스크립트가 이를 모델링하기 위해 구조적 타이핑을 사용한다: 타입스크립트는 자바스크립트의 덕 타이핑 개념을 구조적 타이핑 방식으로 모델링하여, 객체의 구조(속성과 메서드)를 기반으로 타입을 결정하고 정적 타입 검사를 수행합니다.
이해하기 쉽게 말하면, 자바스크립트는 "오리처럼 보이고 행동하면 오리다"라고 간주하는 덕 타이핑 방식을 사용하며, 타입스크립트는 이 개념을 받아들여 객체의 구조를 기반으로 타입을 결정하고 타입 안전성을 높이는 구조적 타이핑 방식을 사용한다는 것입니다.
아이템 5 any타입 지양하기
any타입을 사용하게 되면 타입스크립트의 장점을 잃게 됩니다. any타입은 되도록 지양하자