3 minute read

최초 작성 : 2025-09-16

마지막 수정 : 2025-09-16


세팅

① Node.js가 설치되어 있어야 한다.

② 터미널에 아래와 같은 명령어를 입력한다.

npm install -g typescript

③ (선택) ts → js 변환

tsc -w

터미널에 위와 같은 명령어를 입력하면 ts파일을 js파일로 변환시켜준다.


타입지정

let name: string = 'kim';
let age: number = 20;

 타입스크립트에서는 위와 같이 변수를 만들 때 타입지정이 가능하다. 타입으로 쓸 수 있는 것에는 string, number, boolean, bigint, null, undefined, [], {} 등이 있다.

let names: string[] = ['kim', 'park'];
let fruits: Array<string> = ['apple', 'banana'];

 배열은 위와 같이 타입지정을 할 수 있다.

let user: { name: string; age: number } = {
  name: "kim",
  age: 20
};

 객체는 위와 같이 타입지정을 할 수 있다. 선택적 속성은 ?를 붙인다. (예를 들어, 위의 코드에서 age?: number와 같이 작성했다면 age는 객체에서 작성 안 해도 된다.)

function add(x: number, y: number): number {
    return x + y;
}

 함수에서는 매개변수마다 타입을 지정하며, 함수의 반환 타입도 지정할 수 있다.

let id: string | number = 123;

 |로 여러 타입을 허용할 수 있다. 이를 유니온 타입이라고 한다.

 타입스크립트에서는 두 가지 방식으로 타입지정이 되는데, 위처럼 직접 타입을 작성하는 것을 명시적 타입 (Explicit Type)이라고 하고, 타입스크립트에서 타입을 추론하는 것을 추론적 타입 (Implicit Type)이라고 한다.

 일반적으로는 추론적 타입을 사용하는 것이 좋다. 코드 길이가 짧아지고 간결하기 때문이다. 다만 타입스크립트에서 타입을 추론하지 못하는 경우에는 명시적 타입을 사용한다.


타입 별칭 (Type Alias)

 타입 별칭이란 type키워드를 사용하여 기존 타입에 새로운 이름을 부여하는 것이다. 이를 통해서 임의의 타입을 만들어 사용할 수 있게 되며, 코드를 간결하게 짤 수 있다.

type Player = {
    name: string,
    age?: number
}

const nico: Player = {
    name: "nico"
}

추가 기능

readonly 속성

 readonly를 추가하면 값을 변경할 수 없도록 만들 수 있다.

const Player = {
    readonly name: string,
    age: number
}

 예를 들면 위와 같이 객체의 속성에 사용할 수 있는데, 위의 코드에서 name은 처음 선언된 이후로는 값을 변경할 수 없게 된다.

const numbers: readonly number[] = [1, 2, 3]

 또는 위와 같이 배열에 사용할 수도 있다. readonly로 선언된 배열은 값이 변경되지 않는다.

특수한 타입

 자바스크립트에서는 없는 타입스크립트 전용 타입도 있다.

 any는 어떠한 타입도 사용 가능하게 하며, 타입 체커를 비활성화시킨다.

unknown은 어떠한 타입도 사용 가능하게 하지만, 사용 전에 타입을 검사하게 한다. 안전한 any타입이라고 생각할 수 있다.

let a: unknown;

if (typeof a === 'number') {
    let b = a + 1;
}

 위의 코드에서, 만약 if문으로 a의 범위를 좁히지 않았다면 에러가 발생한다. 이와 같이 unknowntypeof을 사용한 if문과 함께 쓸 수 있다.

 void는 아무것도 반환하지 않는 함수에 사용한다. 따로 지정할 필요는 없다.

 never는 함수가 절대로 return하지 않을 때 사용한다. 주로 return 없이 throw로 예외를 발생시키는 함수에 사용한다.


제네릭

 타입스크립트에서 제네릭이란 타입을 일반화해서 재사용 가능하게 한 것을 말한다.

function identity<T>(value: T): T {
    return value;
}

const a = identity(10);
const b = identity("hello");

 위와 같이 함수의 입력과 출력 타입이 연관된 경우에 사용 가능하다. 각각의 타입별로 함수를 정의할 필요 없이 일반화해서 간결하게 작성이 가능하다는 것이 장점이다.

 함수, 인터페이스, 클래스 등 타입이 사용되는 곳에서 이름 옆에 <T>와 같이 타입 매개변수를 붙여 주는 방식으로 사용한다. 이후에는 그 안에서 T를 타입처럼 사용할 수 있다.

 제네릭은 호출 시그니처를 생성해줄 수 있는 도구라고 생각하면 된다.


추상 클래스

 추상 클래스(abstract class)는 직접 객체를 만들 수 없는 클래스로, 속성이나 메서드를 정의만 해두고 이를 상속받은 하위 클래스에서 구현을 하도록 하는 것이다.

abstract class Animal {
    abstract makeSound(): void;
}

class Dog extends Animal {
	makeSound(): void {
        console.log("멍멍!");
    }
}

const dog = new Dog();

 위와 같이 abstractclass 앞에 붙이며, 이를 다른 클래스에서 상속할 때는 extends를 사용한다.

 상속받은 클래스에서 메서드를 구현하도록 강제할 경우에는 메서드 정의 시 앞에 abstract 키워드를 붙인다. 이를 추상 메서드라고 한다. 단 추상 메서드 외에도 일반 메서드도 포함할 수 있다.

 아래에 나오는 인터페이스와의 차이점은 추상 클래스에서는 메서드 구현도 가능하고 멤버 변수도 선언 가능하다는 것이다. 또한 접근 제한자 (public, private, protected)도 사용 가능하다. 따라서 추상 클래스는 공통된 로직을 재사용할 때, 인터페이스는 형태만 정의하고 구현을 다르게 해야할 때 사용한다.


인터페이스

 interface는 객체의 형태를 정의할 때 사용한다. type으로도 똑같은 것을 할 수 있지만, type는 다양한 용도로 쓸 수 있는 반면에 interface는 오직 객체의 형태를 정의하는 용도로만 사용한다.

interface Animal {
  name: string;
  makeSound(): void;
}

class Dog implements Animal {
  constructor(public name: string) {}
  makeSound() {
    console.log("Woof!");
  }
}

 위의 코드는 Animal이라는 인터페이스를 통해 Dog라는 클래스를 구현한 것인데, 이와 같이 인터페이스를 클래스로 구현할 때는 implements를 사용한다.

 참고로 인터페이스에서 정의된 변수는 클래스 구현 시에 생성자에서 public name: string과 같이 가져올 수 있는데, 이때 중요한 것은 인터페이스 내의 모든 것은 public이기 때문에 클래스에서도 public으로 가져와야 한다는 것이다.

interface Point {
  x: number;
  y: number;
}

const p: Point = { x: 10, y: 20 };

 interface는 클래스와 함께 많이 사용되긴 하지만, 그뿐만 아니라 어떤 객체 타입에든 적용할 수 있다.

interface Named { name: string; }
interface Aged { age: number; }

class Person implements Named, Aged {
  constructor(public name: string, public age: number) {}
}

 여러 개의 interface를 동시에 적용하는 것도 가능하다. 또는 extends로 인터페이스를 확장해 다른 인터페이스를 만들 수도 있다.

Updated: