728x90
728x90

클래스(Class)

들어가며

  • 타입스크립트(TypeScript)에서 사용할 수 있는 클래스(Class)에 대해 정리해본다.

 

클래스(Class)

개념

  • 객체(Object)를 생성하기 위한 설계도(Blueprint)
  • 데이터를 캡슐화하고, 그 데이터를 조작하는 메서드를 포함하여 객체 지향 프로그래밍(OOP, Object Oriented Programming) 패턴을 따른다.
  • 상속(Inheritance)를 지원하며, 복잡한 데이터 구조를 쉽게 생성할 수 있다.

 

클래스와 생성자(Contructor)

  • 클래스에서 생성자(Constructor)새 인스턴스를 생성할 때 호출되는 특별한 메서드이다.
  • 생성자는 보통 객체의 초기 상태를 설정하는 데 사용된다.
class Book {
  // 클래스 속성 선언
  title: string;
  author: string;
  
  // 생성자
  constructor(title: string, author: string) {
    this.title = title;
    this.author = author;
  }
}

const deepWork = new Book('Deep Work', 'Cal Newport');

 

생성자 생성과 동시에 클래스 속성 선언하기

  • 참고로 타입스크립트에서는 @title: string; author: string;@과 같은 클래스 속성 선언이 필요하다.
  • 하지만, 생성자 파라미터접근자를 추가하면, 클래스 속성을 따로 선언하지 않아도 된다.
class Book {
  // 생성자 파라미터에 접근자 추가 -> 따로 클래스 속성을 선언한지 않아도 된다.
  constructor(public title: string, public author: string) {}
}

const deepWork = new Book('Deep Work', 'Cal Newport');

 

인스턴스 속성과 기본값

  • 클래스 내에서 정의된 속성들은 인스턴스 속성(Instance Property)이라고 불리며, 클래스의 각 인스턴스에 대해 고유한 값을 가질 수 있다.
  • 특정 속성은 생성자에서 초기화되지 않으면 기본값(Default Value)을 가질 수도 있다.
class Book {
  title: string;
  author: string;
  checkedOut: boolean = false;  // 기본값 설정
  
  constructor(title: string, author: string) {
    this.title = title;
    this.author = author;
  }
}

const deepWork = new Book('Deep Work', 'Cal Newport');
deepWork.checkedOut = true;   // 인스턴스에서 값 변경하기

 

⇒ @checkedOut@ 속성은 기본적으로 @false@로 설정되지만, 인스턴스에서 값을 변경할 수 있다.

 

읽기전용(Readonly) 수정자

  • @readonly@ 키워드는 해당 속성을 읽기 전용(Readonly)으로 만들어준다.
  • 한 번 설정된 이후에는 해당 속성의 값을 변경할 수 없다.
class Book {
  readonly title: string;   // 읽기전용 설정
  author: string;
  
  constructor(title: string, author: string) {
    this.title = title;
    this.author = author;
  }
}

const deepWork = new Book('Deep Work', 'Cal Newport');
deepWork.title = 'Something else';  // 오류 발생

 

접근 제한자(Access Modifier) : private, public, protected

  • 클래스 내에서 @public@과 @private@, @protected@ 접근 제한자(Access Modifier)를 사용하여 속성 및 메서드의 접근 범위를 제어할 수 있다.
  • @public@은 어디서든 접근 가능하며, @private@은 클래스 내부에서만 접근할 수 있다. 또한 @protected@는 클래스 내부 및 서브 클래스에서만 접근 가능하다.
class Book {
  public readonly title: string;
  public author: string;
  protected checkedOut: boolean = false;  // protected
  private dueDate: Date | null = null;  // private

  constructor(title: string, author: string) {
    this.title = title;
    this.author = author;
  }

  public checkOut() {
    this.checkedOut = this.toggleCheckedOutStatus();
    this.setDueDate();  
  }

  public isCheckedOut() {
    return this.checkedOut;
  }

  protected toggleCheckedOutStatus() { 
    return !this.checkedOut;
  }

  private setDueDate() { 
    const currentDate = new Date();
    const dueDate = new Date(currentDate.setDate(currentDate.getDate() + 14)); 
    this.dueDate = dueDate;
  }

  public getDueDate() { 
    return this.dueDate;
  }
}

// 서브 클래스
class LibraryBook extends Book {
  public libraryId: string;
  private fineAmount: number = 0;  // private 

  constructor(title: string, author: string, libraryId: string) {
    super(title, author);
    this.libraryId = libraryId;
  }

  public checkLibraryStatus() {
    // protected 속성 접근
    return this.checkedOut ? 'Checked out' : 'Available';
  }

  public forceCheckOut() {
    this.checkedOut = true;  // protected 속성 접근
  }

  private calculateFine() {  
    if (this.isCheckedOut()) {
      this.fineAmount += 10;  
    }
  }

  public getFineAmount() { 
    this.calculateFine();
    return this.fineAmount;
  }
}

const deepWork = new LibraryBook('Deep Work', 'Cal Newport', 'LB123');
deepWork.forceCheckOut();

console.log(deepWork.checkLibraryStatus());  // 'Checked out'
console.log(deepWork.isCheckedOut());  // true
console.log(deepWork.getDueDate());  // 2주 후의 날짜 출력
console.log(deepWork.getFineAmount());  // 벌금 조회
// console.log(deepWork.fineAmount);  // 오류 발생 (fineAmount는 private 속성이므로 외부에서 접근 불가)

 

 

접근 제한자(Access Modifier)

접근 제한자 설명 접근 가능
@public@ - 접근 제한자를 명시하지 않으면 @public@으로 간주된다. (기본값) 어디서든 접근 가능
(클래스 내부/외부, 서브 클래스)
@private@ - 클래스 외부 서브 클래스에서 해당 속성이나 메서드에 접근하면 오류가 발생한다.
- 클래스 외부에서 해당 속성이나 메서드에 접근을 막아, 데이터 보호 및 캡슐화를 강화한다.
클래스 내부에서만 접근 가능
@protected@ - 상속 관계에서만 해당 속성이나 메서드를 활용할 수 있도록 하고, 외부 접근은 차단한다.
- @private@과 유사하지만, 서브 클래스에서는 접근이 가능하다.
*서브 클래스 : 해당 클래스를 상속 받은 클래스
클래스 내부서브 클래스에서만 접근 가능

 

  • @public@ 접근 제한자 사용 예
class Book {
  public title: string;  // 명시적으로 public 선언
  author: string;  // 접근 제한자를 생략하면 기본적으로 public
  
  constructor(title: string, author: string) {
    this.title = title;
    this.author = author;
  }
}

const book = new Book('Deep Work', 'Cal Newport');
console.log(book.title);  // 접근 가능
console.log(book.author);  // 접근 가능

 

  • @private@ 접근 제한자 사용 예
class Book {
  private checkedOut: boolean = false;  // 클래스 내부에서만 접근 가능
  
  constructor(public title: string, public author: string) {}
  
  public checkOut() {
    this.checkedOut = true;
  }
  
  public isCheckedOut() {
    return this.checkedOut;
  }
}

const book = new Book('Deep Work', 'Cal Newport');
book.checkOut();
console.log(book.isCheckedOut());  // true
// console.log(book.checkedOut);  // 오류 발생 (private 속성은 클래스 외부에서 접근 불가)

 

  • @protected@ 접근 사용자 사용 예
class Book {
  protected checkedOut: boolean = false;  // 서브 클래스에서 접근 가능
  
  constructor(public title: string, public author: string) {}
}

// LibraryBook 클래스는 Book 클래스를 상속 받는다.
class LibraryBook extends Book {
  constructor(title: string, author: string) {
    super(title, author);
  }
  
  public checkStatus() {
    // 서브 클래스에서 접근 가능
    return this.checkedOut ? 'Checked out' : 'Available';
  }
}

const libraryBook = new LibraryBook('Deep Work', 'Cal Newport');
console.log(libraryBook.checkStatus());  // 'Available'
// console.log(libraryBook.checkedOut);  // 오류 발생 (protected 속성은 클래스 외부에서 접근 불가)

 

축약 문법(Shorthand Syntax)

  • 타입스크립트에서는 클래스 생성자에서 @public@, @private@, @protected@와 같은 접근자를 사용하여 더 간결하게 속성을 정의하고 초기화할 수 있다.
class Book {
  private checkedOut: boolean = false;
  constructor(public readonly title: string, public author: string) {}
}

 

Getter와 Setter

  • Getter와 Setter는 클래스에서 속성의 접근 및 수정을 제어하는 특수한 메서드이다.
  • 호출 시 함수처럼 사용되지 않고, 속성처럼 접근할 수 있다.
  • 호출 할 때 소괄호(@()@)를 붙이지 않는다.
  • GetterSetter로 만들고자 하는 메서드 이름 앞에 @get@ 또는 @set@ 키워드를 붙인다.
class Book {
  private checkedOut: boolean = false;
  
  constructor(public readonly title: string, public author: string) {}
  
  // getter
  get info() {
    return `${this.title} by ${this.author}`;
  }
  
  // getter
  get checkOut() {
    return this.checkedOut;
  }
  
  // getter
  public get someInfo() {
    this.checkOut = true;
    return `${this.title} by ${this.author}`;
  }
  
  // setter
  private set checkOut(checkedOut: boolean) {
    this.checkedOut = checkedOut;
  }
}

const deepWork = new Book('Deep Work', 'Cal Newport');

// 호출할 때, 소괄호를 붙이지 않는다.
console.log(deepWork.info);  
console.log(deepWork.someInfo);
console.log(deepWork.checkOut);

 

Getter와 Setter 메서드를 호출할 때, 소괄호(@()@)를 붙이지 않는다.

 

인터페이스 구현(Implementation of Interface)

  • 타입스크립트에서 인터페이스(Interface)객체 구조에 대한 계약 조건(Contract)을 정의한다.
  • 클래스가 인터페이스구현(Implementation)할 때, 그 클래스는 인터페이스에 정의된 모든 속성메서드를 제공해야 한다.
  • 클래스에서 @implements@ 키워드를 이용하여 인터페이스를 구현할 수 있다.
interface IPerson {
  name: string;
  age: number;
  greet(): void;
}

class Person implements IPerson {
  constructor(public name: string, public age: number) {}

  greet() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }
}

const hipster = new Person('ShakeAndBake', 100);
hipster.greet();

 

클래스를 이용하여 인터페이스를 구현할 때, 클래스에서 '반드시' 인터페이스의 모든 속성과 메서드를 구현해야 한다.

 

참고 사이트

 

Documentation - Classes

How classes work in TypeScript

www.typescriptlang.org

 

728x90
728x90