* 타입스크립트 프로그래밍(보리스 체르니, 프로그래밍 인사이트)를 읽고 요약 정리한 글입니다.
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) 타입스크립트 프로그래밍, 프로그래밍 인사이트, 보리스 체르니,
'TypeScript' 카테고리의 다른 글
[타입스크립트 프로그래밍] 10장 Namespaces.Modules (2) | 2023.06.09 |
---|---|
[타입스크립트 프로그래밍] 9장 프론트엔드 프레임워크와 백엔드 프레임워크 (0) | 2023.06.09 |
[타입스크립트 프로그래밍] 7장 에러처리 (2) | 2023.06.07 |
댓글