본문 바로가기
TypeScript

[타입스크립트 프로그래밍] 5장 클래스와 인터페이스

by 복숭아 우유씨 2023. 5. 31.

* 타입스크립트 프로그래밍(보리스 체르니, 프로그래밍 인사이트)를 읽고 요약 정리한 글입니다.

 
 

Intro. 클래스

클래스
- 객체 지향 프로그래밍 언어에서 중요
- 코드 조직, 이해할 수 있는 방법 제공
- 캡슐화의 주요 단위
 
타입스크립트의 클래스
- 기능 대부분은 C#에서 가져옴

기능 TS/JS 지원 구분 런타임에 코드 존재여부
가시성 접근자, 인터페이스, 제네릭 등 타입스크립트만 지원 X
프로퍼티 초기자, 데코레이터 등 모두 지원 O

 
 

5.1 클래스와 상속

 
접근한정자
타입스크립트는 클래스의 프로퍼티와 메서드에 3가지 접근 한정자를 제공한다.

  접근 가능 범위 기타
public 어디서나 가능 기본값
protected 해당 클래스와 서브클래스의 인스턴스에서만 접근 가능  
private 해당 클래스의 인스턴스에서만 접근 가능  

abstract 
- 추상 클래스, 추상 메서드를 만드는 키워드
 
추상 클래스
- 해당 클래스를 바로 인스턴스화 할 수 없음
- 상속받은 클래스를 통해서만 인스턴스화 할 수 있음
- 메서드 추가 가능
추상 메서드
- 하위 클래스에서 시그니처와 호환되도록 구현해야 한다.
- 즉, 추상 클래스에 추상 메서드가 있을 경우, 상속받는 클래스는 반드시 추상 메서드도 구현해야한다.

추상클래스와 추상메서드, 하위 메서드에서 추상메서드를 구현하지 않으면 에러가 발생한다.

readonly
- 인스턴스 메서드 앞에 붙여서 초기 값 할당 이후 변경 불가하도록 하는 키워드

 

5.2 super

 

 - 타입스크립트에서도 자바스크립트처럼 super를 지원한다.
 - 부모클래스의 메서드에 접근할 수 있게 해준다. (프로퍼티는 아님)
super 호출
 1) 참조 - 메서드 호출
 2) super() - 생성자 함수에서만 호출 가능, 자식클래스의 생성자 함수가 있으면 반드시 호출해야 함
 
 

5.3 this를 반환타입으로 사용하기

- this를 타입으로 사용할 수 있다.
- 활용: 메서드의 반환 타입으로 지정

// methodB를 호출하면 해당 클래스의 인스턴스를 반환해야 하는 경우
class Parent {
	methodA(value: number): boolean {
    	// ...
    }
	methodB(value: number): Parent {
    // 해당 인스턴스를 반환해야 함
    	// ...
    }
    methodB2(value: number): this {
    // 반환타입을 this로 지정함
    	// ...
    }
}

class Child extends Parent {
	methodB(value: number): Child {
    // 자식클래스의 인스턴스를 반환하도록 오버라이드 해야함
    	// ...
    }
	// methodB2 메서드는 오버라이드 할 필요 없음
    // ...
}

- 위의 코드의 methodB2 메서드에서처럼 this를 반환하면 부모와 자식클래스 모두 각각의 인스턴스를 자동으로 가리키므로 자식클래스에서 오버라이드할 필요가 없어진다.
 

5.4 인터페이스

인터페이스
- 타입별칭처럼 타입에 이름을 지어주는 수단
- 클래스에서 많이 사용한다.
 
타입별칭과 인터페이스와의 비교

// type alias (타입 별칭)
type Sushi = {
	calories: number
    salty: boolean
    tasty: boolean
}

// interface (인터페이스)
interface Sushi {
    calories: number
    salty: boolean
    tasty: boolean
}

 

 

  타입 별칭 인터페이스
정의 형태(shape) 정의, 서로 할당 가능4
타입 조합 공통 정보와 인터섹션 사용 상속 사용 (extends 키워드)
오른편에 올 수 있는 것 모든 타입 가능
(타입 표현식도 가능 - 타입과 타입 연산자(&, |))
형태만 가능
상속시 타입 할당 가능 여부 확인 X
타입별칭과 인터섹션을 사용하면 확장하는 타입을 최대한 조합하는 방향으로 동작
-> 오버로드한 시그니처, 에러 발생 X
O
상속받는 인터페이스 타입에 상위 인터페이스를 할당할 수 있는지 확인
-> 에러 검출 가능
선언 합침
(declaration merging)
X
컴파일 에러 발생
O

인터페이스는 상속시 타입 할당 가능 여부를 확인한다.

선언 합침
- 같은 이름으로 정의된 여러 정의를 자동으로 합치는 타입스크립트의 기능
- 열거형, 네임스페이스에서도 사용됨
- 인터페이스에서도 같은 이름으로 중복 정의하면 자동으로 하나로 합친다.
- 단, 인터페이스 끼리 충돌하지 않아야 한다.
   - 같은 이름의 프로퍼티의 타입이 같아야 한다.
   - 제네릭을 선언한 경우 선언방법과 이름까지 같아야 한다.
 
implements
- 클래스 선언시 사용할 수 있는 키워드
- 클래스가 특정 인터페이스를 만족시킴을 표현할 수 있다.
- 타입 수준의 제한 추가하여 구현 문제 파악을 쉽게 해준다.
- 디자인 패턴(어댑터, 팩토리, 전략 등) 구현에도 사용된다.
- 이를 사용한 클래스는 해당하는 모든 메서드를 구현해야 하며, 추가 구현도 가능하다.
- 한 클래스가 여러개의 인터페이스를 구현할 수 있다.

interface Animal {
	readonly name: string // readonly 사용가능
	eat(food: string): void
    sleep(hours: number): void
}

interface Feline {
	meow(): void
}

// implements로 두개의 interface를 구현함
// 빠진 프로퍼티가 있다면 에러가 발생한다.
class Cat implements Animal, Feline {
	// interface Animal
	eat(food: string) {
    	// ...
    }
    // interface Animal
    sleep(hours: number) {
    	// ...
    }
    // interface Feline
    meow() {
		// ...
    }
}

 
키워드
- 인터페이스에서 사용불가한 키워드: 가시성 한정자(private, protected, public), static
- 인터페이스에서 사용가능한 키워드: readonly
 
인터페이스 구현 vs. 추상 클래스 상속

  인터페이스 추상 클래스
목적과 기능 개요 더 범용적, 더 가벼움 특별한 목적과 풍부한 기능
정의 형태를 정의
(객체, 배열, 함수, 클래스, 클래스 인스턴스 정의 가능)
클래스만 정의
런타임에 존재 여부 X
JS코드 만들지 않고, 컴파일 타임에만 존재
O
JS 클래스 코드 만든다.
기능 차이   생성자, 기본 구현, 접근 한정자 지정 가능
목적 가볍게 타입만 명시 여러 클래스에서 공유하는 구현

 

5.5 클래스는 구조 기반 타입을 지원한다.

클래스의 구조 기반 타입 지원
- 이름이 아닌 구조를 기준으로 삼는 구조 기반 타입을 지원한다.
- 형태를 공유하는 다른 모든 타입과 호환된다.
- 단, 클래스에 private, protected 필드가 있고, 할당하려는 클래스나 서브클래스의 인스턴스가 아니라면 할당 할 수 없다
 

5.6 클래스는 값과 타입을 모두 선언한다.

- 타입스크립트에서 값과 타입은 별도의 네임스페이스에 존재하며, 사용시 문맥을 파악해 해석한다.
- 클래스와 열거형의 경우, 둘을 동시에 생성한다.
 
생성자 시그니처
- new 연산자
- 해당 타입을 인스턴스화 할 수 있음을 정의하는 타입스크립트의 방식
- 구조 기반으로 타입을 구분하기에 클래스가 무엇인지 기술하는 최선의 방식 (클래스란 new로 인스턴스화 할 수 있는 어떤 것)
- 인수를 받는 생성자도 선언 가능
 

5.7 다형성

클래스와 인터페이스도 제네릭 타입 매개변수 기능을 지원한다.
 
클래스에서 제네릭 타입 범위
- class와 함께 선언시 클래스 전체
- 특정 인스턴스 메서드에서 선언시 특정 메서드로 한정됨
 
클래스의 제너릭 타입
- constructor에는 제너릭 타입 선언 불가
- 클래스 수준 제네릭은 클래스 내부 어디서나 사용 가능
- 인스턴스 메서드는 클래스 수준 제네릭 사용 가능하며, 추가적으로 자신만의 제네릭을 선언할 수도 있음
- 정적메서드에서는 클래스 수준의 제네릭 사용 불가 (자신만의 제네릭 직접 선언해야 함)
 
인스턴스에서의 제네릭
- 구체 타입 명시하거나 추론하도록 할 수 있음
 

5.8 믹스인

trait, mixin
-JS, TS에서 제공하는 키워드는 아니나 구현 가능
- 다중 상속(둘 이상의 클래스 상속받음)과 관련된 기능 제공
- 역할 지향 프로그래밍(is-a 관계 대신 can, has-a 관계 사용, 속성을 묘사하는 방식)을 제공
 
믹스인
- 동작과 프로퍼티를 클래스로 혼합할 수 있게 해주는 패턴
- 다음 규칙을 따름
  1) 상태를 가질 수 있다.
  2) 구체 메서드만 제공할 수 있다. 
  3) 생성자를 가질 수 있다.
 
타입스크립트에서의 믹스인
- 내장 기능은 아니나 구현 가능 (클래스 생성자를 인수로 받아 클래스 생성자를 반환하는 함수로 구현)
 

5.9 데코레이터

- 타입스크립트의 실험적 기능
- 클래스, 클래스 메서드, 프로퍼티, 메서드 매개변수를 활용한 메타 프로그래밍에 깔끔한 문법을 제공
- 장식하는 대상의 함수를 호출하는 기능을 제공
- 클래스를 감싸고 선택적으로 이를 대체하는 새 클래스를 반환
- 데코레이터 타입 각각에 대해 주어진 이름 범위에 존재하는 함수와 해당 데코레이터 타입에 요구되는 시그니처를 필요로 함
- 타입스크립트에서 기본적으로 제공하는 데코레이터는 없으며, 특정 시그니처를 만족하는 일반 함수일 뿐
- 장식하는 대상의 형태를 바꾸지 않는다고 가정함
- 반환된 클래스를 전달된 클래스에 할당할 수 있는지는 컴파일 타임에만 확인함.
 

5.10 final 클래스 흉내내기

final 키워드
- 클래스나 메서드를 확장하거나 오버라이드 할 수 없게 만드는 기능
- 타입스크립트에서 private constructor로 흉내 낼 수 있음 
  : 생성자를 private으로 선언하면, new로 인스턴스를 생성하거나 클래스를 확장할 수 없다.
- 상속만 막으려면 클래스를 반환하는 static create등의 메서드를 추가하면 된다.
 

5.11 디자인 패턴

팩토리 패턴
- 어떤 객체를 만들지를 전적으로 팩토리에 위임하는 패턴
빌더 패턴
- 객체의 생성과 객체 구현 방식을 분리하는 패턴
 
 


reference
1) 타입스크립트 프로그래밍, 프로그래밍 인사이트, 보리스 체르니, 

 
 
 

댓글