본문 바로가기
카테고리 없음

TypeScript 23강: 클래스와 상속을 활용한 객체지향 프로그래밍

by mystory55776 2025. 5. 23.

TypeScript에서 클래스(Class)란?

TypeScript는 자바스크립트를 기반으로 하는 언어로, 객체지향 프로그래밍(OOP)을 지원하기 위해 클래스 개념을 제공합니다. class 키워드를 사용하여 객체의 구조와 동작을 정의할 수 있으며, 생성자, 속성, 메서드를 포함할 수 있습니다. 객체지향 설계를 통해 코드의 재사용성과 유지보수성이 높아집니다.

기본 클래스 구조

TypeScript에서 클래스를 선언하는 기본 형태는 다음과 같습니다:

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  greet(): void {
    console.log(`안녕하세요, 저는 ${this.name}입니다.`);
  }
}

const user = new Person("홍길동", 30);
user.greet(); // 안녕하세요, 저는 홍길동입니다.

클래스 내부에는 생성자(constructor)를 통해 객체 생성 시 초기값을 전달하며, 메서드를 통해 객체의 동작을 정의할 수 있습니다.

접근 제어자: public, private, protected

TypeScript 클래스는 접근 제어자를 통해 클래스 멤버의 접근 범위를 지정할 수 있습니다.

  • public: 클래스 외부에서도 접근 가능 (기본값)
  • private: 클래스 내부에서만 접근 가능
  • protected: 클래스 자신과 상속받은 클래스에서 접근 가능
class User {
  public name: string;
  private password: string;

  constructor(name: string, password: string) {
    this.name = name;
    this.password = password;
  }

  private showPassword(): void {
    console.log(this.password);
  }
}

private 속성과 메서드는 외부에서 접근할 수 없기 때문에 보안이 필요한 정보에 적합합니다.

클래스 상속(Inheritance)의 개념

TypeScript는 상속을 지원하여 기존 클래스를 확장한 새로운 클래스를 만들 수 있습니다. extends 키워드를 사용해 상속을 구현하며, 부모 클래스의 속성과 메서드를 자식 클래스에서 재사용하거나 오버라이드할 수 있습니다.

class Animal {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  move(): void {
    console.log(`${this.name}가 움직입니다.`);
  }
}

class Dog extends Animal {
  bark(): void {
    console.log("멍멍!");
  }
}

const myDog = new Dog("초코");
myDog.move(); // 초코가 움직입니다.
myDog.bark(); // 멍멍!

이처럼 Dog 클래스는 Animal 클래스를 상속받아 move() 메서드를 그대로 사용하고, 새로운 기능인 bark()를 추가합니다.

super 키워드의 사용

자식 클래스에서 부모 클래스의 생성자 또는 메서드를 호출할 때는 super 키워드를 사용합니다. 반드시 자식 클래스의 생성자에서 super()를 먼저 호출해야 부모 클래스의 속성이 올바르게 초기화됩니다.

class Employee {
  constructor(public name: string) {}

  getInfo(): string {
    return `이름: ${this.name}`;
  }
}

class Manager extends Employee {
  constructor(name: string, public department: string) {
    super(name); // 부모 생성자 호출
  }

  getInfo(): string {
    return `${super.getInfo()}, 부서: ${this.department}`;
  }
}

const manager = new Manager("이순신", "개발팀");
console.log(manager.getInfo()); // 이름: 이순신, 부서: 개발팀

super.getInfo()를 통해 부모 클래스의 메서드를 호출하고, 추가적인 정보를 덧붙여 확장할 수 있습니다.

메서드 오버라이딩 (Method Overriding)

상속받은 메서드를 자식 클래스에서 재정의(오버라이딩)할 수 있습니다. 이때 부모의 메서드를 유지하면서 일부만 수정하거나 확장하는 방식으로 유용하게 사용됩니다.

class Vehicle {
  drive(): void {
    console.log("차량이 이동합니다.");
  }
}

class Car extends Vehicle {
  drive(): void {
    console.log("자동차가 도로를 달립니다.");
  }
}

const myCar = new Car();
myCar.drive(); // 자동차가 도로를 달립니다.

Car 클래스는 Vehicledrive() 메서드를 자신의 방식으로 다시 정의합니다.

추상 클래스와 추상 메서드

추상 클래스는 인스턴스를 생성할 수 없으며, 반드시 상속을 통해 사용됩니다. 추상 메서드는 구현을 강제하는 목적에서 사용되며, 자식 클래스에서 구현해야 합니다.

abstract class Shape {
  abstract getArea(): number;
}

class Circle extends Shape {
  constructor(public radius: number) {
    super();
  }

  getArea(): number {
    return Math.PI * this.radius ** 2;
  }
}

Shape 클래스는 추상 클래스이며, getArea() 메서드는 추상 메서드로 자식 클래스인 Circle에서 반드시 구현해야 합니다.

클래스와 인터페이스의 조합 사용

TypeScript에서는 클래스가 implements 키워드를 통해 인터페이스를 구현할 수 있습니다. 이 방식은 다형성을 높이고 코드의 일관성을 유지하는 데 유리합니다.

interface Printable {
  print(): void;
}

class Report implements Printable {
  print(): void {
    console.log("리포트를 출력합니다.");
  }
}

Printable 인터페이스를 구현한 Report 클래스는 반드시 print() 메서드를 포함해야 하며, 이를 통해 일정한 규약을 강제할 수 있습니다.

결론: 객체지향 프로그래밍의 핵심을 TypeScript로 구현하기

TypeScript의 클래스와 상속은 객체지향 프로그래밍(OOP)의 핵심 개념인 추상화, 캡슐화, 상속, 다형성을 효과적으로 구현할 수 있게 해줍니다. 클래스를 사용하면 구조화된 코드를 작성할 수 있고, 상속을 통해 중복을 줄이며 유지보수성을 높일 수 있습니다. 실제 프로젝트에서도 타입 안정성과 개발 생산성을 동시에 확보하려면 TypeScript의 클래스 기능을 적극 활용하는 것이 중요합니다.