
"TypeScript is JavaScript with syntax for types"
타입스크립트는, 기존 자바스크립트 문법에 타입을 가미한 것
타입스크립트를 통해, 타입체크를 정적으로 런타임이 아닌 빌드 (트랜스파일) 과정에서 수행할 수 있게 해준다.
JS 코드 → AST (추상 문법 트리) 생성 → 바이트코드 변환 → 실행 TS 코드 → AST 생성 → 타입 검사 → JS로 변환(트랜스파일) → AST (추상 문법 트리) 생성 → 바이트코드 변환 → 실행단, 타입스크립트는 자바스크립트의 슈퍼셋일 뿐이라, JS에서 안되는건 TS에서도 불가능
any는 사실상 타입스크립트가 제공하는 정적 타이핑의 이점을 모두 버리는 것이나 다름없다.
any는 모든 타입을 커버하기에, 어떤 상황에서도 런타임 과정에서 타입 에러를 잡아내지 못한다.
(예외적인 상황이 아니라면 사용하지 않는게 좋음 )
아직 타입을 단정할 수 없는 경우에는 unknown을 사용하는 것이 좋다.
- unknown이란 모든 값을 할당할 수 있는 top type 이면서, 또 해당 값을 바로 사용하는 것이 불가능하기에 type 좁히기를 통해서 사용해야 하기에 타입에러를 잡아낼 수 있기도 하다.
function doSomething(callback: unknown) {
// type narrowing
if (typeof callback === 'function') {
callback();
return;
}
throw new Error('callback은 함수여야 합니다.');
}
한편, unknown과 반대되는 bottom type인 never가 있기도 하다.
never는 어떠한 타입도 들어올 수 없음을 의미한다.
type what1 = string & number
type what2 = ('hello' | 'hi') & 'react'
첫번째 타입은 문자열이면서, 숫자인 타입은 존재할 수 없으니 never가 선언되며,
두번째 타입의 경우, 교차점이 없기에 마찬가지로 코드상에서 존재 불가한 타입으로 나타난다.
항상 예외를 던지는 함수(반환값이 필요없는 경우)
// throw를 만나면 실행 중단 -> 반환값이 존재할 수 없음
function throwError(message: string): never {
throw new Error(message);
}
타입가드란 - 타입을 좁히는데 도움을 줄 수 있는 것으로, instanceof 나 typeof , in을 이용한 조건문을 이용한다
[] instanceof Array 를 정확히 판별할 수 있다. interface Student {
age: number;
score: number;
}
interface Teacher {
name: string;
}
function doSchool(person: Student | Teacher) {
if ("age" in person) {
// 이때, person은 Student 타입
}
if ("name" in person) {
// 이때, person은 Teacher 타입
}
}
단일 타입이 아닌, 다양한 타입에 대응할 수 있도록 하는 타입도구이다.
이때 제네릭을 하나 이상 사용할 수 있다.
function multipleGeneric<First, Last>(a1: First, a2: Last): [First, Last] {
return [a1, a2];
}
const [a, b] = multipleGeneric<string, boolean>("true", true);
console.log(a); // string
console.log(b); // boolean
인덱스 시그니처란, 객체 키를 정의하는 방식을 의미한다.
일반적인 인덱스 시그니처:
type Hello = { [key: string]: string };
Record를 사용하거나, 더 좁게 인덱스 시그니처를 설정하거나, 그것도 아니면 as로 key 타입 단언을 하는 편이 좋다. Record<K, V>는 객체의 키(K)와 값(V)의 타입을 명확하게 지정할 때 사용하는 유틸리티 타입이다.
// Record를 사용
type HeUo = Record<'hello' | 'hi', string>;
const hello: HeUo = {
hello: 'hello',
hi: 'hi',
};
// 타입을 사용한 인덱스 시그니처
type HeUo = { [key in 'hello' | 'hi']: string };
const hello: HeUo = {
hello: 'hello',
hi: 'hi',
};
key as keyof Hello 를 통해 key가 반드시 hello 나 hi를 포함하고 있다는 것을 ts에게 알려주는 타입 단언을 해줄 수 있다.
type Helo = { hello: string, hi: string };
const hello: Hello = {
hello: 'Hello!',
hi: 'Hi!',
};
// Object.keys()는 string[]을 반환하기 때문에
// key를 keyof Hello 타입으로 단언하여 정확한 타입을 지정
Object.keys(hello).map((key) => {
const value = hello[key as keyof Hello]; // key를 keyof Hello로 단언
return value;
});
타입스크립트 전환을 위해, 가장 먼저 해야할 것은 ts 작성이 가능한 환경을 만들어주는 것이다.
최상위 디렉터리에 tsconfig 파일을 만들어주자.
{
"compilerOptions": {
// .ts 또는 .js 파일로 컴파일된 결과물이 저장될 폴더로, TypeScript의 컴파일 결과는 이 폴더로 이동
"outDir": "./dist",
// .js 파일을 ts 프로젝트 내에서 허용할지 여부를 설정하는 옵션
// Js 파일이 존재하는 과도기적인 프로젝트에서 true로 설정하면 함께 작업할 수 있음
"allowJs": true,
// TypeScript 코드가 어떤 JavaScript 버전으로 변환될지를 지정
"target": "es5"
},
// TypeScript 컴파일러가 트랜스파일할 파일을 지정
// `./src/**/*`는 src 폴더 내 모든 .ts 및 .js 파일을 포함함!
"include": ["./src/**/*"]
}