클래스 정의


자바스크립트에선 생성자 내부에서 프로퍼티를 선언하고 초기화한다. 클래스 필드를 사용하는 경우를 제외하곤 클래스 바디에 프로퍼티를 따로 선언할 필요가 없다. 반면 타입스크립트에선 먼저 클래스 바디에 프로퍼티를 미리 선언하고 타입을 지정해야 한다. 클래스 바디에 프로퍼티를 선언하지 않으면 에러가 발생한다.

class User {
	name: string; // 프로퍼티 선언 및 타입 지정

	constructor(name: string) {
		this.name = name; // 프로퍼티 초기화
	}
}

const user = new User('John');
console.log(user); // { name: 'John' }

타입스크립트에선 public, protected, private 접근 제한자를 별도로 제공하는데, 생성자 파라미터에 접근 제한자를 사용하면 암묵적으로 클래스 프로퍼티를 선언하고 초기화가 진행된다. 즉, 생성자 파라미터에 접근 제한자를 사용하면 클래스 바디에 프로퍼티를 선언한 것과 동일한 효과를 얻을 수 있다. 일일이 프로퍼티를 선언하고 생성자 내에 초기화 코드를 작성하지 않아도 돼서 코드가 더욱 간결해진다.

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

const user = new User('John');
console.log(user); // { name: 'John' }

접근 제한자 Access Modifier


자바스크립트에서 클래스와 프로퍼티는 기본적으로 public으로 선언된다. 타입스크립트 역시 동일하지만 이를 더 명시적으로 표현할 수 있는 public 접근 제한자를 제공한다.

자바스크립트에서 프로퍼티 혹은 메서드 이름 앞에 # 기호를 붙이면 클래스 내부에서만 접근할 수 있는 private 멤버로 선언된다. 타입스크립트에선 private 키워드를 사용하여 접근 제한을 더 명시적으로 표현할 수 있다.

접근 가능한 곳 public protected private
클래스 내부 O O O
자식 클래스 내부 O O X
클래스 인스턴스 O X X

<aside> <img src="/icons/search_gray.svg" alt="/icons/search_gray.svg" width="40px" /> 프로토타입에 저장된 메서드도 클래스 내부로 취급한다

</aside>

public

public 접근 제한자는 클래스 내부, 자식 클래스 내부, 인스턴스에서 자유롭게 접근할 수 있는 멤버를 의미한다. 아무런 키워드를 붙이지 않았을 땐 기본적으로 public 멤버로 취급된다.

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

  public printName() {
    console.log(this.name); // 클래스 내부에서 public 프로퍼티 접근
  }
}

const user = new User('John'); // { name: 'John' }
user.name; // 'John'
user.printName(); // 'John'

protected

protected 접근 제한자는 해당 클래스와 자식 클래스 내부에서만 접근할 수 있는 멤버를 의미한다. 아래 예시에서 name 프로퍼티와 sayHello() 메서드는 protected 멤버이므로 인스턴스에선 직접 접근할 수 없다.

class User {
  constructor(protected name: string) {}

  protected sayHello() {
    console.log(`${this.name}, Hello`);
  }
}

class PaidUser extends User {
  public printName() {
    console.log(this.name); // 자식 클래스 내부에서 protected 프로퍼티 접근
  }

  public callSayHello() {
    this.sayHello(); // 자식 클래스 내부에서 protected 메서드 접근
  }
}

const paidUser = new PaidUser('John'); // { name: 'John' }
paidUser.name; // Error! (인스턴스에서 접근 불가)
paidUser.sayHello(); // Error! (인스턴스에서 접근 불가)

paidUser.printName(); // 'John'
paidUser.callSayHello(); // 'John, Hello'

한편 paidUser.printName() 메서드를 호출하면 에러가 발생하지 않는다. printName() 메서드를 호출하면 상속 받은 자식 클래스인 PaidUser 내부에서 name 프로퍼티에 접근하기 때문이다.