TYPESCRIPT

(Typescript) 타입 선언 방법 3탄, 클래스 타입 선언 방법

Znero 2024. 6. 22. 15:18

 

 

이전 포스팅으로 객체와 변수, 함수 등의 타입 선언 방법에 대해 다루었다.

 

이번 포스팅에서는 클래스의 타입을 선언하는 방법에 대해서 정리하고자 한다.

 

타입스크립트의 클래스 선언 방법은 자바스크립트와 유사하지만, 

 

접근 제어자, getter/setter, 인터페이스, abstract 클래스 등 타입스크립트만의 고유 기능이 있으며

 

이 기능들을 활용하면 좀 더 명확하고 안정성이 높은 코드를 짤 수 있다. 

 

 

 

1.  클래스의 타입 선언 방법 / constructor 단축구문

클래스의 타입을 설정하는 타입스크립트의 기본 문법은 아래와 같다.

 

자바스크립트의 클래스 선언과 동일하게 필드 선언과 초기화(constructor)가 들어가 있고, 여기에 타입이 추가된다.

class User {
  name: string;
  age: number;

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

 

이때 constructor 단축구문을 활용하면 필드 선언과 초기화를 한 번에 할 수 있다.

class User {
  constructor(
    public name: string, 
    public age: number
  ) {}
}

 

 

 

2.  제어자 (public, protected, private, readonly)

자바스크립트와 달리 타입스크립트에는 제어자가 존재한다. 

 

제어자는 클래스 필드에 대한 접근을 제어할 수 있다. 

  • public: 기본 접근 제어자, 어디에서든 접근 가능
  • private: 클래스 내부 및 서브클래스에서만 접근 가능
  • protected: 클래스 내부 및 해당 클래스의 인스턴스에서만 접근 가능
  • readonly: 읽기 전용 속성으로, 클래스 내부에서만 수정할 수 있음
class Animal {
    constructor(
      public name: string, 
      private type: string, 
      protected age: number, 
      readonly species: string
    ) {}
}

class Dog extends Animal {
    constructor(name: string, age: number) {
        super(name, 'Dog', age, 'Canine'); //부모 클래스로부터 상속
    }
    getDogAge(): number {
        return this.age;
    }
}

const dog = new Dog('Buddy', 5);
console.log(dog.name); // public 속성이라 자유롭게 접근 가능
console.log(dog.getDogAge()); // private 속성이라 get 메서드로 접근
// console.log(dog.type); // 에러 발생:private 속성
// dog.species = 'Feline'; // 에러 발생:readonly 속성

 

 

 

3.  getter & setter

자바스크립트와 동일하게 getter와 setter을 활용해 private 필드에 안전하게 접근할 수 있다. 

class User {
  constructor(
    public name: string, 
    private _age: number
  ) {}
  
  get age(): number{
    return this._age;
  }
  set age(newAge: number){
    if(newAge<0){
      throw new Error("Age cannot be negative!");
    }
    this._age = newAge;
  }
}

const lily = new User("lily", 20);
lily.age //get 20
lily.age = 50 //set 50

 

 

 

4. 인터페이스를 활용한 선언

인터페이스를 활용해 클래스를 선언할 수도 있다.

 

특정 인터페이스로 클래스를 구현하려면, implement 키워드를 사용하면 된다.

interface Name{
  name: string;
  sayHi(): void;
}

class User implements Name{
  constructor(
    public name: string, 
    private _age: number
  ) {}
  
  sayHi(): void {
    console.log(`Hi, my name is ${this.name}`);
  }
}

const lily = new User("lily", 20);
lily.sayHi(); //Hi, my name is lily

 

 

 

5.  abstract 클래스

abstract 키워드를 붙인 추상 클래스는 자신의 인스턴스를 생성할 수 없다.

 

추상 클래스는 다른 클래스가 반드시 구현해야 하는 메서드를 정의할 수 있다.

 

이런 점에서 추상 클래스는 인터페이스와 유사하지만 차이점이 있다.

추상 클래스는 인터페이스와 달리 구현을 가질 수 있으며, 스태틱 메서드와 속성도 가질 수 있다.

 

이로 인해 추상 클래스는 인터페이스보다 더 유연한 구조를 제공한다.

 

  • 추상 메서드 (abstract)
    • abstract 키워드를 사용
    • 구현이 없어야 함
    • 서브클래스에서 반드시 구현해야 함
  • 일반 메서드 
    • 구현을 가짐
    • 서브 클래스에서 재정의(오버라이드) 가능
    • 인스턴스에 속하며, 인스턴스를 통해 호출
    • this 키워드로 인스턴스 속성에 접근 가능
  • 정적 메서드 (static)
    • static 키워드를 사용
    • 클래스 자체에 속하며, 클래스를 통해 호출
    • this 키워드로 해당 클래스의 정적 속성에 접근 가능
    • 인스턴스에 접근 불가
abstract class Name {
  constructor(public name: string, public age: number) {}

  // 추상 메서드: 서브클래스에서 반드시 구현해야 함
  abstract sayHi(): void; 

  // 스태틱 메서드
  static saySpecies(): void {
    console.log("I'm human");
  }

  // 일반 메서드 
  sayAge(): void {
    console.log(`I am ${this.age} years old.`);
  }
}

class User extends Name {
  constructor(name: string, age: number) {
    super(name, age);
  }

  // 추상 메서드 구현
  sayHi(): void {
    console.log(`Hi, my name is ${this.name}.`);
  }
}

const user = new User('Alice', 30);
user.sayHi(); // "Hi, my name is Alice." //추상 메서드
user.sayAge(); // "I am 30 years old." //일반 메서드
Name.saySpecies(); // "I'm human" //스태틱 메서드