icon
4장 : 클래스와 인터페이스

클래스 기본 문법


자바스크립트는 프로토타입 기반 객체 지향 언어이지만, ES2015(ES6)부터는 다른 객체 지향 언어와 유사한 클래스(Class) 문법을 제공하기 시작했습니다. 클래스는 객체 지향 프로그래밍의 핵심 개념인 추상화, 캡슐화, 상속, 다형성을 구현하는 데 사용되는 문법적 설탕(Syntactic Sugar)입니다. 타입스크립트는 이 자바스크립트의 클래스 문법에 강력한 타입 시스템을 더하여 클래스를 더욱 안전하고 견고하게 만들 수 있도록 돕습니다.

이번 절에서는 타입스크립트의 클래스 기본 문법과 핵심 요소들을 상세히 살펴보겠습니다.


클래스 선언과 인스턴스 생성

클래스를 선언하는 것은 class 키워드를 사용하며, 일반적으로 클래스 이름은 파스칼 케이스(PascalCase, 첫 글자 대문자)를 사용합니다.

// 'Person'이라는 이름의 클래스를 선언합니다.
class Person {
  // 1. 속성 (Property): 클래스의 데이터를 나타냅니다.
  // 각 속성에도 타입을 명시합니다.
  name: string;
  age: number;
  private _job: string; // private 접근 제어자를 가진 속성

  // 2. 생성자 (Constructor): 클래스의 인스턴스가 생성될 때 호출됩니다.
  // 인스턴스의 속성들을 초기화하는 역할을 합니다.
  constructor(name: string, age: number, job: string) {
    this.name = name; // this는 현재 생성되는 인스턴스를 가리킵니다.
    this.age = age;
    this._job = job;
  }

  // 3. 메서드 (Method): 클래스의 동작(함수)을 나타냅니다.
  // 매개변수와 반환 값에 타입을 명시합니다.
  greet(): string {
    return `안녕하세요, ${this.name}입니다. 저는 ${this.age}살이고 ${this._job}입니다.`;
  }

  // Getter (속성 값을 읽을 때 사용)
  get job(): string {
    return this._job;
  }

  // Setter (속성 값을 설정할 때 사용)
  set job(newJob: string) {
    if (newJob.length < 2) {
      console.log("직업명은 2글자 이상이어야 합니다.");
      return;
    }
    this._job = newJob;
  }
}

// 클래스의 인스턴스 (객체) 생성
// new 키워드와 함께 생성자를 호출합니다.
const person1 = new Person("김철수", 30, "개발자");
const person2 = new Person("이영희", 25, "디자이너");

console.log(person1.name); // 김철수
console.log(person1.age);  // 30
console.log(person1.greet()); // 안녕하세요, 김철수입니다. 저는 30살이고 개발자입니다.

// Getter 사용
console.log(person2.job); // 디자이너

// Setter 사용
person2.job = "마케터";
console.log(person2.greet()); // 안녕하세요, 이영희입니다. 저는 25살이고 마케터입니다.

person2.job = "SE"; // setter에 정의된 조건에 의해 변경되지 않음
console.log(person2.job); // 마케터 (변경되지 않음)

클래스의 기본적인 구성 요소는 다음과 같습니다.

  • 속성 (Properties): 클래스의 상태를 나타내는 변수입니다. 각 속성에도 타입을 명시합니다. (예: name: string;)
  • 생성자 (Constructor): new 키워드를 통해 클래스의 인스턴스를 생성할 때 호출되는 특별한 메서드입니다. 인스턴스의 초기 상태를 설정하는 역할을 합니다.
  • 메서드 (Methods): 클래스가 수행할 수 있는 동작을 나타내는 함수입니다. 일반 함수와 마찬가지로 매개변수와 반환 값에 타입을 명시할 수 있습니다.
  • this 키워드: 클래스 내부에서 this는 현재 클래스의 인스턴스를 가리킵니다. 이를 통해 인스턴스의 속성과 메서드에 접근할 수 있습니다.
  • Getter/Setter: 특정 속성에 대한 읽기/쓰기 접근을 제어하는 메서드입니다. 속성처럼 접근하지만 내부적으로는 함수가 실행됩니다.

접근 제어자

타입스크립트의 클래스는 속성과 메서드의 접근 수준을 제어하는 세 가지 접근 제어자(Access Modifiers) 를 제공합니다. 이는 객체 지향의 캡슐화(Encapsulation) 를 구현하는 데 중요한 역할을 합니다.

public (공개): 가장 기본적인 접근 제어자입니다. 선언된 속성이나 메서드가 클래스 외부에서 자유롭게 접근 가능함을 의미합니다. 아무런 접근 제어자를 명시하지 않으면 기본적으로 public으로 간주됩니다.

class PublicExample {
  public value: number; // public 명시
  message: string;      // 기본값 public

  constructor(val: number, msg: string) {
    this.value = val;
    this.message = msg;
  }

  public display(): void {
    console.log(`Value: ${this.value}, Message: ${this.message}`);
  }
}

const pe = new PublicExample(10, "Hello");
console.log(pe.value);   // 10 (접근 가능)
pe.display();            // Display: Value: 10, Message: Hello (접근 가능)

private (비공개): 선언된 속성이나 메서드가 해당 클래스 내부에서만 접근 가능함을 의미합니다. 클래스 외부나 상속받은 자식 클래스에서도 접근할 수 없습니다. 이는 특정 데이터를 외부에서 직접 변경하지 못하도록 보호할 때 유용합니다.

class PrivateExample {
  private secretCode: string; // private 속성

  constructor(code: string) {
    this.secretCode = code;
  }

  public revealCode(): string {
    return `비밀 코드: ${this.secretCode}`; // 클래스 내부에서 접근 가능
  }
}

const pve = new PrivateExample("MY_PRIVATE_KEY");
// console.log(pve.secretCode); // Error: Property 'secretCode' is private and only accessible within class 'PrivateExample'.
console.log(pve.revealCode()); // 비밀 코드: MY_PRIVATE_KEY (public 메서드를 통해 간접 접근)

자바스크립트의 # 프라이빗 필드 문법과 유사하나, 타입스크립트의 private는 컴파일 시점에 검사되는 타입 시스템 레벨의 제약입니다.

protected (보호된): 선언된 속성이나 메서드가 해당 클래스 내부와 이 클래스를 상속받은 자식 클래스 내부에서만 접근 가능함을 의미합니다. 클래스 외부에서는 접근할 수 없습니다. 이는 부모 클래스의 특정 속성이나 메서드를 자식 클래스에서 활용해야 하지만, 외부 노출은 막고 싶을 때 사용됩니다.

class ProtectedExample {
  protected protectedValue: string; // protected 속성

  constructor(value: string) {
    this.protectedValue = value;
  }

  protected getProtectedValue(): string {
    return this.protectedValue;
  }
}

class ChildExample extends ProtectedExample {
  constructor(value: string) {
    super(value); // 부모 클래스의 생성자 호출
  }

  public printProtected(): void {
    console.log(`자식에서 접근: ${this.protectedValue}`);     // 자식 클래스에서 접근 가능
    console.log(`자식에서 메서드 접근: ${this.getProtectedValue()}`); // 자식 클래스에서 메서드 접근 가능
  }
}

const child = new ChildExample("보호된 값");
child.printProtected(); // 자식에서 접근: 보호된 값, 자식에서 메서드 접근: 보호된 값
// console.log(child.protectedValue); // Error: Property 'protectedValue' is protected and only accessible within class 'ProtectedExample' and its subclasses.

생성자의 매개변수에 접근 제어자 사용하기

타입스크립트에서는 생성자의 매개변수에 직접 접근 제어자(public, private, protected, readonly)를 붙여서, 해당 매개변수를 클래스의 속성으로 동시에 선언하고 초기화할 수 있는 편리한 문법을 제공합니다.

class CompactPerson {
  // 매개변수에 public을 붙여 자동으로 속성으로 선언하고 초기화
  constructor(public name: string, public age: number, private _secretInfo: string) {
    // this.name = name; 이런 식으로 속성 할당 코드를 생략할 수 있습니다.
  }

  get secretInfo(): string {
    return this._secretInfo;
  }
}

const compactP = new CompactPerson("김효진", 28, "비밀 일기");
console.log(compactP.name);       // 김효진
console.log(compactP.age);        // 28
// console.log(compactP._secretInfo); // Error: private 속성이므로 접근 불가
console.log(compactP.secretInfo); // 비밀 일기 (getter를 통해 접근)

이 방식은 코드를 훨씬 간결하게 만들어주며, 특히 클래스 속성 정의와 생성자 초기화 코드를 줄이는 데 효과적입니다.


static 속성과 메서드

클래스의 static (정적) 멤버는 클래스의 인스턴스가 아닌, 클래스 자체에 속하는 속성이나 메서드입니다. 즉, new 키워드로 인스턴스를 생성하지 않고도 클래스 이름으로 직접 접근할 수 있습니다. 유틸리티 함수나 모든 인스턴스가 공유해야 하는 상수 값 등을 정의할 때 유용합니다.

class MathUtil {
  static PI: number = 3.14159; // 정적 속성

  static calculateCircleArea(radius: number): number { // 정적 메서드
    return this.PI * radius * radius; // 정적 메서드 내에서 정적 속성 접근 시 this.PI
  }

  // 인스턴스 메서드에서는 정적 멤버에 직접 접근하지 않는 것이 일반적입니다.
  // 다만 클래스 이름으로 접근은 가능합니다.
  public getInstancePi(): number {
    return MathUtil.PI; // 클래스 이름으로 접근
  }
}

// 인스턴스 생성 없이 직접 클래스 이름으로 접근
console.log(MathUtil.PI); // 3.14159
console.log(MathUtil.calculateCircleArea(5)); // 78.53975

const util = new MathUtil();
console.log(util.getInstancePi()); // 3.14159 (인스턴스를 통해 정적 속성 접근)

// 오류: 인스턴스를 통해 정적 메서드에 접근할 수 없습니다.
// util.calculateCircleArea(10); // Error: Property 'calculateCircleArea' does not exist on type 'MathUtil'. Did you mean 'static calculateCircleArea'?

static 멤버는 클래스명 뒤에 점(.)을 찍어 접근합니다. this를 사용하면 같은 클래스 내의 다른 static 멤버에 접근할 수 있습니다.


클래스는 복잡한 애플리케이션의 구조를 체계적으로 설계하고 관리하는 데 필수적인 요소입니다. 타입스크립트는 자바스크립트의 클래스 문법에 타입 안전성과 접근 제어자 같은 객체 지향적 기능을 추가하여, 더욱 견고하고 유지보수하기 쉬운 코드를 작성할 수 있도록 돕습니다.