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
클래스는 Vehicle
의 drive()
메서드를 자신의 방식으로 다시 정의합니다.
추상 클래스와 추상 메서드
추상 클래스는 인스턴스를 생성할 수 없으며, 반드시 상속을 통해 사용됩니다. 추상 메서드는 구현을 강제하는 목적에서 사용되며, 자식 클래스에서 구현해야 합니다.
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의 클래스 기능을 적극 활용하는 것이 중요합니다.