TypeScript는 간단하게 말해서 타입을 강제하는 JavaScript라고 할 수 있습니다.

JavaScript에 대한 지식이 있는 분이 읽는다는 가정하에 작성합니다.
TypeScript 공식문서의 스펙을 보면서 생각한 차이에 대해 핵심을 정리한 글입니다.

선언시에 타입을 명시해야한다

let isDone: boolean = false;
let decimal: number = 6;

이런 식으로 변수자체 타입을 정해주어야합니다.

let color: string = 'bluer';
color = 'red';

선언 후에 재할당시에는 JavaScript와 같습니다.

배열의 경우엔

let list1: number[] = [1,2,3];
let list2: Array<number> = [1,2,3];

두가지 방법으로 작성할 수 있습니다.

Tuple

let x: [string, number];
x = ["hello", 10];

이런식으로 배열의 사이즈와 각 인덱스의 타입을 강제할 수 있습니다. 사이즈를 벗어난 인덱스를 참조하거나 각 인덱스의 타입과 다른 타입을 재할당 할 수 없습니다.

Enum

JavaScript의 객체와 비슷하며,
숫자 값에 알기 쉬운 네이밍을 주는 방법입니다.

enum Color {Red, Green, Blue}
let c: Color = Color.Green;
console.log(c); // output: 1

Red, Green, Blue는 순서대로 0,1,2의 밸류를 가지고 있습니다.

enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;
console.log(c); // output: 2

시작 값을 1로 바꾸어주면 뒤의 값들도 같이 바뀝니다.
또한, 아래와 같은 방식으로 각각 지정해 줄 수도 있습니다.

enum Color {Red = 1, Green = 2, Blue = 4}

반대로, 값으로부터 키 값을 구할 수도 있습니다.

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];

console.log(colorName); // Displays 'Green' as its value is 2 above

참고로, 여기서 Color[2]는 Color의 2번째 인덱스가 아니라, 2라는 밸류를 갖고있는 키값을 의미합니다.

Any

동적인 타입을 가지는 변수(타입을 하나로 고정하지 않을 변수)는 Any라는 타입을 씁니다.

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

또한, 배열의 원소들의 타입이 여러가지일 경우에는

let list: any[] = [1, true, "free"];
list[1] = 100;

이런 방식으로 지정 가능합니다.

Void

Void는 비어있다는 의미입니다.
TypeScript는 function의 parameter와 return value도 타입을 명시해주어야하는데,
주로 return value가 없을 때 Void를 활용합니다.

function warnUser(): void {
    console.log("This is my warning message");
}

변수에도 void 타입을 강제할 수 있지만, null과 undefined이외엔 할당할 수 없기때문에, 별로 유용하지 않습니다.

let unusable: void = undefined;
unusable = null

참고로, --strictNullChecks가 설정이 되어있지 않은 경우에만 가능합니다.

Null and Undefined

undefined와 null도 각자의 타입을 가집니다.

let u: undefined = undefined;
let n: null = null;

이것 또한 null이나 undefined값만 가질 수 있기 때문에 사용할 일이 적을 수 있습니다.

기본적으로 null과 undefined는 모든 타입의 서브타입이기 때문에 다른 타입에도 null이나 undefined를 할당할 수 있습니다.

그러나 --strictNullChecks flag를 사용하면 null과 undefined는 any타입과 스스로의 타입이외엔 할당할 수 없습니다. (undefined는 void타입에도 할당 가능합니다)

string, null or undefined 타입을 넘기고 싶다면, string | null | undefined 타입을 이용하면 됩니다.

Never

값을 리턴하지 않을 때 사용합니다.

// Function returning never must have unreachable end point
function error(message: string): never {
    throw new Error(message);
}

// Inferred return type is never
function fail() {
    return error("Something failed");
}

// Function returning never must have unreachable end point
function infiniteLoop(): never {
    while (true) {
    }
}

Object

declare function create(o: object | null): void;

create({ prop: 0 }); // OK
create(null); // OK

create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error

Type assertions

any로 선언해두고 참조할 때 타입을 assert합니다.(단언하다라는 뜻인데, 대충 string일거라고 판단하겠다는 뜻입니다.)
그래서 someValue는 any 타입이지만 string타입의 메소드인 .length를 사용할 수 있습니다.
하지만, 실제로 string이 아닐 경우엔 에러를 출력하지않고, 강제로 타입 변환이 수행하지는 않습니다.)

두가지 방식으로 사용할 수 있습니다.

let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;
let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;