ts-for-jsdev
  • 자바스크립트 개발자를 위한 타입스크립트
  • 들어가며
  • 01 타입스크립트 소개
    • 1.0 들어가며
    • 1.1 정적 타입 분석
    • 1.2 왜 타입스크립트인가
    • 1.3 타입스크립트의 구성요소
    • 1.4 타입스크립트의 역사
  • 02 ECMAScript
    • 2.0 ECMAScript
    • 2.1 블록 수준 스코프
      • 2.1.1 let을 이용한 선언
      • 2.2.2 const를 이용한 선언
      • 2.2.3 스코프 베스트 프랙티스
    • 2.2 객체와 배열
      • 2.2.1 비구조화 할당
      • 2.2.2 나머지 연산자와 전개 연산자
      • 2.2.3 객체 리터럴 변경사항
    • 2.3 함수
      • 2.3.1 기본 매개변수
      • 2.3.2 화살표 함수
    • 2.4 템플릿 리터럴
      • 2.4.1 멀티라인 문자열
      • 2.4.2 문자열 치환
    • 2.5 원소 순회
      • 2.5.1 forEach 메소드
      • 2.5.2 for-of 문법
      • 2.5.3 이터레이터 프로토콜
      • 2.5.4 이터러블 프로토콜
    • 2.6 비동기 처리
      • 2.6.1 프로미스
      • 2.6.2 Async / Await
    • 2.7 맺으며
  • 03 타입스크립트 기초 문법
    • 3.0 타입스크립트 기초 문법
    • 3.1 기본 타입
    • 3.2 배열과 튜플
    • 3.3 객체
    • 3.4 타입 별칭
    • 3.5 함수
    • 3.6 제너릭
    • 3.7 유니온 타입
    • 3.8 인터섹션 타입
    • 3.9 열거형
  • 04 인터페이스와 클래스
    • 4.0 들어가며
    • 4.1 인터페이스 기초
    • 4.2 색인 가능 타입
    • 4.3 인터페이스 확장
    • 4.4 클래스
    • 4.5 클래스 확장
    • 4.6 클래스 심화
      • 4.6.1 스태틱 멤버
      • 4.6.2 접근 제어자
      • 4.6.3 접근자
      • 4.6.4 추상 클래스
    • 4.7 인터페이스와 클래스의 관계
    • 4.8 맺으며
  • 05 타입의 호환성
    • 5.0 들어가며
    • 5.1 기본 타입의 호환성
    • 5.2 객체 타입의 호환성
    • 5.3 함수 타입의 호환성
    • 5.4 클래스의 호환성
    • 5.5 제너릭의 호환성
    • 5.6 열거형의 호환성
    • 5.7 맺으며
  • 06 타입 시스템 심화
    • 6.0 들어가며
    • 6.1 타입 좁히기
    • 6.2 타입 추론
    • 6.3 타입 단언
    • 6.4 집합으로서의 타입
    • 6.5 서로소 유니온 타입
    • 6.6 맺으며
  • 07 고급 타입
    • 들어가며 (7월 2일 공개)
  • 08 모듈과 네임스페이스
    • 들어가며 (7월 16일 공개)
  • 09 실제 프로젝트에서 사용하기
    • 들어가며 (7월 30일 공개)
  • 10 유용한 라이브러리 소개
    • 들어가며 (8월 13일 공개)
    • 맺으며
  • 부록 II : 자바스크립트 언어 생태계
    • ECMAScript 언어 표준과 TC39
    • TC39 프로세스
    • 실제 예시 - Array.prototype.includes
    • 타입스크립트와 ECMAScript
Powered by GitBook
On this page
  • 생성자
  • 속성
  • 속성 기본값
  • 읽기 전용 속성
  • 메소드
  1. 04 인터페이스와 클래스

4.4 클래스

객체 지향적 구조화 수단인 클래스에 대해 다룬다.

ES6에는 기존의 객체 지향 언어와 비슷하게 클래스를 선언할 수 있는 class 키워드가 추가되었다. 타입스크립트의 클래스는 ES6 클래스의 상위집합으로, ES6 클래스를 포함할 뿐 아니라 여러 추가기능을 제공한다. 가장 간단한 형태의 클래스는 다음과 같다.

class NothingImportant {}

이렇게 정의된 클래스는 new 키워드를 이용해 인스턴스화(instantiation) 할 수 있다. 클래스는 인스턴스를 찍어내는 일종의 틀로 생각할 수 있다.

const nothingImportant: NothingImportant = new NothingImportant()

A라는 클래스를 정의할 때, 이름은 같지만 의미는 다른 두 식별자가 동시에 생성된다는 점에 주의하라.

  • 타입 A: A 클래스 인스턴스의 타입 (const a: A)

  • 함수 A: new 키워드와 함께 호출되는 클래스 A의 생성자 (new A())

예를 들어, const a: A = new A() 라는 코드에서 앞의 A는 인스턴스의 타입을 가리키는 반면, 뒤의 A는 해당 클래스의 생성자, 즉 함수 타입의 값이다.

생성자

constructor 키워드를 사용해 클래스 생성자(class constructor)를 정의할 수 있다. 만약 어떤 클래스가 생성자를 정의하지 않았다면, 본문이 비어있는 함수가 생성자로 사용된다. (constructor() {} )객체 생성자와 유사하게, 클래스 생성자를 통해 클래스 인스턴스가 생성될 때 실행될 로직을 정의할 수 있다.

class Dog {
  constructor() {
    console.log('constructing!');
  }
}
const dog: Dog = new Dog(); // constructing!

생성자는 임의의 매개변수를 취할 수 있다. 이 변수들은 클래스를 인스턴스화 할 때 인자로 넘겨진다. 예를 들어, 아래에서는 생성자의 barkingSound 매개변수에 들어갈 값으로 인자 '월' 을 넘기고 있다.

class BarkingDog {
  constructor(barkingSound: string) {
    console.log(`${barkingSound}!`);
  }
}

const barkingDog: BarkingDog = new BarkingDog('월'); // 월!

생성자의 함수 시그니쳐와 맞지 않는 타입의 인스턴스화를 시도할 시 에러가 발생한다.

const err: BarkingDog = new BarkingDog(); 
// error TS2554: Expected 1 arguments, but got 0.

const err2: BarkingDog = new BarkingDog(3); 
// error TS2345: Argument of type '3' is not assignable to parameter of type 'string'.

속성

객체 속성과 유사하게 클래스 인스턴스도 속성(property)를 가질 수 있다. 클래스 내에서는 속성엔 this 키워드를 이용해 접근 가능하다. 모든 클래스 속성은 이름: 타입 꼴의 속성 선언(property declaration)을 통해 타입을 표기해주어야 한다.

class Triangle {
  // 속성 선언
  vertices: number;
  constructor() {
    // 속성 할당
    this.vertices = 3;
  }
}
const triangle: Triangle = new Triangle();
console.log(triangle.vertices); // 3

--strictPropertyInitialization 옵션

앞서 3장의 첫 부분에서 우리는 --strict 컴파일러 옵션이 켜진 환경을 가정한다 언급한 적 있다. --strict 옵션은 --strictPropertyInitialization 옵션을 포함한다. 이 옵션이 켜진 환경에선 undefined 를 포함하지 않는 클래스 속성이 반드시 속성 선언 또는 생성자, 두 장소 중 한 곳에서 초기화 되어야 한다.

생성자와 속성 선언 두 곳 모두에서 초기화되지 않는 경우 속성 값이 undefined일 가능성이 존재한다. 따라서 타입스크립트는 그 정보가 타입에 포함되어 있지 않다면 타입 에러를 낸다. 다음 예시를 보자.

class User {
  private password: string;
}
// error TS2564: Property 'password' has no initializer and is not definitely assigned in the constructor.

password는 속성 선언에서도, 생성자에서도 초기화되지 않고 있으므로 접근되는 시점에 undefined 일 수 있다. 이 값은 string 타입이 아니므로 타입 에러가 발생하는 것이 합당하다. 이 에러를 없애기 위해선 두 가지 방법이 존재한다.

  • 실제 상황을 정확히 반영하기 위해 password을 선택 속성으로 선언한다.

    • 즉 password: string 를 password?: string (또는 password: string | undefined) 로 변경한다.

  • password가 undefined여서 문제가 생길 일이 없다고 확신한다면, 속성 이름 뒤에 느낌표(!)를 붙여 확정적 할당 단언(definitive assignment assertion)을 제공할 수 있다.

    • 즉 password: T를 password!: T로 변경한다. 이 경우 컴파일러는 password의 초기화 체크를 건너뛴다.

속성 기본값

함수의 기본 인자와 유사하게 클래스 속성에도 기본값을 제공할 수 있다.

class Triangle {
  vertices: number = 3;
}
const triangle: Triangle = new Triangle();
console.log(triangle.vertices); // 3

읽기 전용 속성

readonly 키워드를 사용해 읽기 전용 속성을 정의할 수 있다. 속성 선언 또는 생성자 외의 장소에서는 읽기 전용 속성에 값을 할당 할 수 없다.

class Triangle {
  readonly vertices: number;
  constructor() {
    this.vertices = 3;
  }
}
const triangle: Triangle = new Triangle();
triangle.vertices = 4;
// error TS2540: Cannot assign to 'vertices' because it is a constant or a read-only property.

이 때, 읽기 전용 속성은 --strictPropertyInitialization 옵션 여부와 무관하게 반드시 속성 선언 또는 생성자에서 초기화되어야 한다. 읽기 전용이라는 정의 자체에 의해 그 두 곳 이외에선 할당 자체가 불가능하기 때문이다. 만약 둘 중 어느 곳에서도 초기화 되지 않았다면 에러가 발생한다.

class Triangle {
  vertices: number;
  readonly angles: number[];
  constructor() {
    this.vertices = 3;
  }
}
// error TS2564: Property 'angles' has no initializer and is not definitely assigned in the constructor.

메소드

객체의 단축 메소드명과 유사한 문법을 사용해 인스턴스의 메소드를 정의할 수 있다. 메소드 내에서는 this 키워드를 사용해 해당 메소드가 호출되는 인스턴스를 참조할 수 있다. 예를 들어, 메소드를 사용해 위의 예제를 아래와 같이 변경할 수 있다.

class BarkingDog {
  barkingSound: string;
  
  constructor(barkingSound: string) {
    this.barkingSound = barkingSound;
  }
  
  bark(): void {
    console.log(`${this.barkingSound}!`);
  }
}
const barkingDog: BarkingDog = new BarkingDog('월');
barkingDog.bark(); // 월!

위에서처럼 함수를 속성으로 정의한 경우엔 별도의 속성 선언이 필요하지만, 메소드 문법을 사용할 경우 속성 선언을 생략할 수 있다.

Previous4.3 인터페이스 확장Next4.5 클래스 확장

Last updated 6 years ago