프로그래밍 언어를 배우는 이유는 실제로 사용하는 프로그램을 만들기 위해서이고, 실제로 사용하는 프로그램에서 에러가 발생하는 것은 문제가 된다. 자바스크립트 프로그램을 타입스크립트로 바꾸면 안정성이 늘어나고 에러가 덜 발생하게 된다. 다만, 타입스크립트가 자바스크립트의 모든 에러를 잡아주는 것은 아니고 실수를 줄여준다고 보면 된다.
타입스크립트는 자바스크립트보다 자유도가 떨어질 수 있다는 단점도 있지만, 실무에서는 자유도보다는 에러를 줄이는 것을 더 중시해야 한다.
TypeScript는 최종적으로 JavaScript로 변환된다.
TypeScript는 언어이자 컴파일러(tsc)이다. 컴파일러는 ts 코드를 js로 바꿔준다.
tsc는 tsconfig.json에 따라 ts 코드를 js로 바꿔준다. 인풋인 ts와 아웃풋인 js 모두에게 영향을 미치므로 tsconfig.json 설정을 반드시 확인해야 한다.
ts 코드를 js 코드로 바꾸는 것이 아니라 단순히 타입 검사만 하고 싶다면 tsc --noEmit 하면 된다.
ts 파일을 실행하는 것이 아니라 결과물인 js를 실행해야 한다.
VS Code나 WebStorm 같은 에디터가 필수이다.
기본적으로 자바스크립트의 변수, 속성, 매개변수, 리턴값에 타입이 붙은 것을 타입스크립트라고 생각하면 된다. 타입은 항상 소문자로 시작해야 한다.
const a: string = '5';
const b: number = 5;
const c: boolean = true;
const d: undefined = undefined;
const e: null = null;
const f: any = true;
const obj: { lat: number, lon: number } = { lat: 37.5, lon: 127.5 };
이때 any 타입은 아무 타입이나 적용이 되기 때문에, 타입스크립트가 아니라 자바스크립트로 인식이 되는것과 마찬가지이다. 그렇기 때문에 any를 최대한 쓰지 않는 것을 목표로 해야 한다.
function add(x: number, y: number): number { return x + y }
//const add: (x: number, y: number) => number = (x, y) => x + y;
type Add = (x: number, y: number) => number;
const add: Add = (x, y) => x + y;
함수의 경우에는 매개변수 뒤에 리턴값 타입을 선언해주며, 화살표 함수 역시 같은 방법으로 타이핑할 수 있지만, type을 별도로 분리해주어 선언할 경우 더 가독성이 좋은 코드를 작성할 수 있다. 타입스크립트는 타입을 지웠을 때 자바스크립트 코드가 나와야 하는 연습을 해야 한다.
interface Add {
(x: number, y: number): number
}
const add: Add = (x, y) => x + y;
interface 역시 타입을 선언해주는 방법 중에 하나이다.
const arr: string[] = ['123', '456'];
const arr2: Array<number> = [123, 456];
const arr3: [number, number, string] = [123, 456, '789'];
배열은 위와 같은 방법으로 타입을 지정해주며, arr2는 제네릭 타입, arr3은 tuple로 배열의 길이가 고정된 타입이다.
const f: true = true;
const g: 5 = 5;
위와 같은 고정된 원시값을 타입을 아예 지정해줄 수도 있다.
let aa = 123;
aa = 'hello' as unknown as number;
타입스크립트에서는 시스템이 추론 및 분석한 타입 내용을 변환해줄 수도 있다. 이때 "타입 표명(type assertion)"이라 불리는 매커니즘이 사용되는데, TypeScript의 타입 표명은 프로그래머가 컴파일러에게 타입에 더 잘 알고 있다는 가정하에 사용된다.
타입스크립트는 자바스크립트보다 자유도가 낮아진다는 단점이 있지만, 실무에서도 타입을 갑자기 변환해주는 일은 거의 없기 때문에 자유도 측면에서 단점이라고 여길 수 없다.
try {
const array = [];
array[0];
} catch(error) {
error;
}
타입스크립트에서 빈 배열은 never라는 타입으로 지정된다. 타입스크립트에서 never 타입은 값의 공집합이다. 집합에 어떤 값도 없기 때문에, never 타입은 any 타입의 값을 포함해 어떤 값도 가질 수 없다.
숫자 체계에 아무것도 없는 양을 나타내는 0처럼 문자 체계에도 불가능을 나타내는 타입이 필요하다.
"불가능"이라는 단어 자체는 모호하다. 타입스크립트에서는 "불가능"을 아래와 같이 다양한 방법으로 나타내고 있다.
값을 포함할 수 없는 빈 타입
제네릭과 함수에서 허용되지 않는 매개변수
호환되지 않는 타입들의 교차 타입
빈 합집합(무의 합집합)
실행이 끝날 때 호출자에게 제어를 반환하지 않는 함수의 반환 타입
절대로 도달할수 없을 esle 분기의 조건 타입
거부된 프로미스에서 처리된 값의 타입
const head = document.querySelector('#head')!;
console.log(head);
const head = document.querySelector('#head');
if (head) {
console.log(head);
}
타입스크립트에서 !는 Definite Assignment Assertions으로 해당 변수의 타입을 확신할 경우에 붙여줄 수 있다. 하지만, 타입이 변할 수도 있고 타입을 확신하는 것은 에러가 발생할 수 있기 때문에 사용을 지양하고 if문을 사용하는 편이 좋다.
type World = "world" | "hell";
const a: World = 'world';
const b: `hello ${a}`;
//type Greeting = 'hello world'
type Greeting = `hello ${World}`;
const c: Greeting = 'hell'
const enum EDirection {
Up,
Down,
Left,
Right,
}
const a = EDirection.Up // 0
const b = EDirection.Left // 2
enum은 열거형 변수로 정수를 하나로 합칠 때 편리한 기능이다. 임의의 숫자나 문자열을 할당할 수 있으며 하나의 유형으로 사용해서 버그를 줄일 수 있다.
type A = { a: string };
const a: A = { a: 'hello' };
interface B { a: string };
const b: B = { a: 'hello' };
간단한 타입을 지정하고 싶을 때는 type, 객체지향형 프로그래밍을 구현하고 싶을 때는 interface를 사용하는 편이 좋다.
function add(x: string | number, y: string | number): string | number { return x + y }
// union, 여러 속성 중 하나만 있어도 된다.
const result: string | number = add(1, 2);
result.charAt()
add('1', '2')
add(1, '2')
type A = { hello: 'world' } & { name: 'kyeom' };
// intersection, 모든 속성이 다 있어야 한다.
const a: A = { hello: 'world', name: 'kyeom' };
type Animal = { breath: true };
type Mammal = Animal & { breed: true };
type Human = Mammal & { think: true };
const Kyeom: Human = { breath: true, breed: true, think: true };
|
는 Union이라 부르며, 또는 관계이기 때문에 타입을 여러개 넣을 수 있다. 그러나 타입스크립트는 모든 경우의 수를 고려하기 때문에, 타입 추론이 잘 되지 않는다는 단점이 있다. 타입스크립트를 사용할 때에는 처음 타입을 제대로 선언하지 않으면 이후의 모든 코드가 에러가 발생할 위험이 있다.
&
는 여러개의 타입이 모두 만족할때에 사용한다. 보통 객체에 사용하며, 객체의 모든 속성이 타입과 같아야 한다. 상속의 개념으로 생각하면 편하다.
interface A {
talk: () => void;
}
interface A {
eat: () => void;
}
interface A {
laugh: () => void;
}
const a: A = { talk() {}, eat() {}, shit() {} }
interface는 여러번 선언할 수 있으며, 선언할 때마다 합쳐지게 된다. 라이브러리들은 대다수가 interface로 선언되어 있으며, 사용자가 추가적으로 수정할 수 있다. void는 자바스크립트에 없는 키워드로, 함수에 해당 함수가 아무것도 반환하지 않는다는 것을 명시해주는 타입이다.