인터페이스 구현 VS 추상 클래스 상속 인터페이스 구현은 추상 클래스 상속과 아주 비슷합니다. 하지만 인터페이스가 더 범용으로 쓰이며 가벼운 반면, 추상 클래스는 특별한 목적과 풍부한 기능을 갖는다는 점이 다릅니다. 인터페이스 인터페이스는 형태를 정의하는 수단입니다. 값 수준에서 이는 객체, 배열, 함수, 클래스, 클래스 인스턴스를 정의할 수 있다는 뜻입니다. 인터페이스는 아무런 JavaScript 코드를 만들지 않으며 컴파일 타임에만 존재합니다. 추상 클래스 추상 클래스는 오직 클래스만 정의할 수 있습니다. 예상할 수 있겠지만 추상 클래스는 런타임의 JavaScript 클래스 코드를 만듭니다. 추상 클래스는 생성자와 기본 구현을 가질 수 있으며 프로퍼티와 메서드에 접근 한정자를 지정할 수 있습니다. 위..
구현 클래스를 선언할 때 implements라는 키워드를 이용해 특정 인터페이스를 만족 시킴을 표현할 수 있습니다. 다른 명시적인 타입 어노테이션처럼 implements로 타입 수준의 제한을 추가하면 구현에 문제가 있을 때 어디가 잘못되었는지 쉽게 파악할 수 있습니다. 또한 어댑터(adapter), 팩토리(factory), 전략(strategy) 등 흔한 디자인 패턴을 구현하는 대표적인 방식이기도 합니다. implements는 아래처럼 사용할 수 있습니다. interface Animal { eat(food: string): void sleep(hours: number): void } class Dog implements Animal { eat(food: string){ console.info('Ate s..
선언 합침(declaration merging) 선언 합침은 같은 이름으로 정의된 여러 정의를 자동으로 합치는 TypeScript의 기능입니다. 이번 글에선 인터페이스라는 맥락에서 간단하게 선언 합침을 살펴보겠습니다. 예를 들어 Member라는 똑같은 이름의 인터페이스를 두 개 정의하면 TypeScript는 자동으로 둘을 하나의 인터페이스로 합칩니다. // Member는 name이라는 한 개의 필드를 가짐 interface Member { name: string } // 여기서 Member는 name과 age 두 개의 필드를 가짐 interface Member { age: number } let a : Member = { name: 'Linda', age: 24 } 이 코드를 타입 별칭으로 표현하면 아래..
인터페이스 클래스는 인터페이스를 통해 사용할 때가 많습니다. 타입 별칭처럼 인터페이스도 타입에 이름을 지어주는 수단이므로 인터페이스를 사용하면 타입을 더 깔끔하게 정의할 수 있습니다. 타입 별칭과 인터페이스는 문법만 다를 뿐 거의 같은 기능을 수행하며, 작은 몇몇 부분에서만 차이를 보입니다. 먼저 둘의 공통점을 살펴보겠습니다. 아래 코드는 타입 별칭입니다. type RiceCake = { calories: number salty: boolean tasty: boolean } 이 코드를 다음처럼 간단하게 인터페이스로 바꿀 수 있습니다. interface RiceCake { calories: number salty: boolean tasty: boolean } RiceCake 타입 별칭을 사용한 모든 곳에 ..
this를 반환 타입으로 사용하기 this를 값뿐 아니라 타입으로도 사용할 수 있습니다. 클래스를 정의할 때라면 메서드의 반환 타입을 지정할 때 this 타입을 유용하게 활용할 수 있습니다. 예를 들어 ES6의 Set 자료구조를 두 가지 연산만 지원하도록 간단히 구현해 보겠습니다. 이 자료구조는 아래처럼 사용할 수 있습니다. // tslint:disable-next-line: new-parens let set = new Set set.add(1).add(2).add(3) set.has(3) // true set.has(4) // false Set 클래스의 has 메서드부터 정의합니다. class Set{ has(value: number): boolean { // ... } } add를 호출하면 Set 인..
super JavaScript처럼 TypeScript도 super 호출을 지원합니다. 자식 클래스가 부모 클래스에 정의된 메서드를 오버라이드하면 자식 인스턴스는 super를 이용해 부모 버전의 메서드를 호출할 수 있습니다. TypeScript는 다음처럼 두 가지 super 호출을 지원합니다. super.take 같은 메서드를 호출합니다. 생성자 함수에서만 호출할 수 있는 super()라는 특별한 타입의 생성자를 호출합니다. 자식 클래스에 생성자 함수가 있다면 super()를 호출해야 부모 클래스와 정상적으로 연결됩니다. (깜빡하고 잊으면 TypeScript가 경고를 해주니까 걱정할 필요가 없습니다.) super로 부모 클래스의 메서드에만 접근할 수 있고 프로퍼티엔 접근할 수 없다는 사실을 기억합시다.
클래스와 상속 체스 엔진을 만들려고 합니다. 해당 엔진은 두 명이 체스를 둘 수 있는 API를 제공합니다. 먼저 타입부터 정의해 보겠습니다. // 체스 게임 class Game{} // 체스 말 class Piece{} // 체스 말의 좌표 집합 class Position{} 체스에는 여섯 가지의 말(piece)이 있습니다. // 체스 게임 class Game{} // 체스 말 class Piece{} // 체스 말의 좌표 집합 class Position{} class King extends Piece {} // 킹 class Queen extends Piece{} // 퀸 class Bishop extends Piece{} // 비숍 class Knight extends Piece{} // 나이트 cl..
타입 주도 개발 강력한 타입 시스템은 큰 힘을 준다고 합니다. 그래서 TypeScript로 코드를 구현할 때 '타입을 추종하는' 자신을 발견하게 될 것이라고 합니다. 사람들은 이것을 타입 주도 개발이라 부릅니다. 타입 주도 개발(type-driven development) 타입 시그니처를 먼저 정하고 값을 나중에 채우는 프로그래밍 방식 표현식이 수용할 수 있는 값의 타입을 제한하는 것이 정적 타입 시스템의 핵심입니다. 표현력이 더 풍부한 타입 시스템일수록 표현식 안의 값을 더 잘 설명할 수 있습니다. 표현력이 높은 타입 시스템을 함수에 적용하면 함수 타입 시그니처를 통해 함수에 관하여 원하는 거의 모든 정보를 얻을 수 있습니다. function map(array: T[], f: (item: T) => U..
제네릭 타입 기본값 함수 매개변수에 기본값을 설정할 수 있듯이 제네릭 타입 매개변수에도 기본 타입을 지정할 수 있습니다. type SecondEvent = { target: T type: string } 새 이벤트를 만들려면 제네릭 타입을 SecondEvent로 명시적으로 한정하여 이벤트가 발생한 HTML 요소를 정확히 가리켜야 합니다. type SecondEvent = { target: T type: string } let buttonEvent: SecondEvent = { target: secondEvent, type: string } 특정 요소 타입을 알 수 없는 때를 대비해 SecondEvent의 제네릭 타입에 기본값을 추가할 수 있습니다. type SecondEvent = { target: T ..