TypeScript에서 클래스 문법을 작성하는 방법과 TypeScript에서 사용할 수 있는 추가 문법에 대해 아래의 예시 코드와 함께 살펴보도록 하겠습니다.
예시 1
class UserA {
constructor(first: string, last: string, age: number) {
this.first = first; // 타입 에러 발생
this.last = last; // 타입 에러 발생
this.age = age; // 타입 에러 발생
}
getAge() {
return `${this.first} ${this.last} is ${this.age}`; // 타입 에러 발생
}
}
클래스 UserA는 constructor 함수에서 매개 변수 first, last, age의 타입을 명해주고 있으며, 각각의 매개 변수를 this 키워드를 사용한 속성에 할당하고 있습니다. 또한 각각의 속성에 할당된 값을 이용하여 getAge 메서드에서 문자를 반환하고 있습니다.
기존 JS에서는 문제가 되지 않는 코드지만 타입스크립트에서는 this로 접근할 수 있는 각각의 속성들이 constructor 함수가 만들어지기 전에 클래스 body 부분에서 타입이 명시되어 있어야 합니다.
위와 같이 constructor 함수 이전에 클래스 body 부분에 속성에 대한 타입을 명시해주게 되면 타입 에러는 사라지게 됩니다.
이렇게 클래스에서 각각의 속성을 지정할 때는 속성 앞에 접근 제어자를 붙여줘야 하기 때문에 아래에서 간단하게 살펴보고 넘어가도록 하겠습니다.
접근 제어자 (Access Modifiers) : 접근을 위해 붙이는 수식어
- public : 어디서나 자유롭게 접근이 가능한 속성으로 public의 경우 클래스의 body에서 생략이 가능합니다.
class UserA {
first: string; // 접근제어자 public 생략
last: string; // 접근제어자 public 생략
age: number; // 접근제어자 public 생략
constructor(first: string, last: string, age: number) {
this.first = first;
this.last = last;
this.age = age;
}
getAge() {
return `${this.first} ${this.last} is ${this.age}`;
}
}
lass UserB extends UserA {
getAge() {
return `${this.first} ${this.last} is ${this.age}`;
}
}
class UserC extends UserB {
getAge() {
return `${this.first} ${this.last} is ${this.age}`;
}
}
즉, 접근 제어자 public을 사용할 경우 생략할 수 있기 때문에 속성 앞에 별도의 접근 제어자가 붙어있지 않은 first, last, age의 경우 앞에 접근 제어자 public이 생략되어 있습니다.
클래스 UserA를 상속받은 클래스 UserB의 경우 별도의 속성에 대한 타입 명시 없이 this를 사용할 수 있는 이유는 클래스 UserA에서 속성에 접근 제어자를 public으로 설정해주었기 때문에 상속받는 클래스에서 접근이 가능하기 때문입니다.
클래스 UserC의 경우도 클래스 UserA를 상속받는 클래스 UserB를 상속받고 있기 때문에 타입 에러가 발생하지 않습니다.
*접근 제어자 public의 경우 생략이 가능하지만 명시적으로 public을 붙여주는 것도 좋습니다.
- protected : 나와 파생된 후손 클래스 내에서 접근이 가능합니다.
class UserA {
first: string;
protected last: string;
age: number;
constructor(first: string, last: string, age: number) {
this.first = first;
this.last = last;
this.age = age;
}
getAge() {
return `${this.first} ${this.last} is ${this.age}`;
}
}
class UserB extends UserA {
getAge() {
return `${this.first} ${this.last} is ${this.age}`;
}
}
class UserC extends UserB {
getAge() {
return `${this.first} ${this.last} is ${this.age}`;
}
}
const rati = new UserA("rati", "Lee", 5);
console.log(rati.first);
console.log(rati.last); // 타입 에러 발생
console.log(rati.age);
*여기서 말하는 "나"는 UserA를 의미하며, 파생된 후손 클래스는 UserA를 상속받아 사용하는 UserB나 UserB를 상속받아 사용하는 UserC를 의미합니다.
코드는 public 예시 코드와 유사하며, 추가로 last 속성의 접근 제어자를 protected로 설정해주었고 하단에서 클래스 UserA를 생성자 함수를 사용해 생성하고 인스턴스 내부의 각각의 속성을 콘솔로 출력하고 있습니다.
이 경우 접근 제어자가 protected로 설정된 속성을 사용하는 부분의 코드에서 타입 에러가 발생하게 되는데, 이는 해당 속성이 protected로 보호되어 있고 클래스 내부에서만 사용이 가능하기 때문입니다.
즉, 접근 제어자 protected를 사용한 속성은 자신을 포함한 하위 후손 클래스 내부에서만 사용이 가능합니다.
- private : 클래스 자신에서만 접근이 가능합니다.
접근 제어자 private를 사용하여 속성을 설정하게 되면 클래스 자신, 즉 UserA 클래스 내부에서만 해당 속성 사용이 가능해집니다.
때문에 클래스 UserA를 상속받는 클래스 UserB에서는 접근 제어자 private로 설정된 age 속성에 접근이 불가능하여 타입 에러가 발생하며, UserA를 상속받는 클래스 UserB를 상속받는 클래스 UserC에서도 age 속성에 접근이 불가능하기 때문에 타입 에러가 발생하게 됩니다.
클래스 UserA 인스턴트의 age 속성에 접근하여 콘솔로 출력하는 코드 역시 동일한 이유로 타입 에러가 발생하게 됩니다.
class UserA {
public first: string;
protected last: string;
private age: number;
constructor(first: string, last: string, age: number) {
this.first = first;
this.last = last;
this.age = age;
}
private getAge() {
return `${this.first} ${this.last} is ${this.age}`;
}
}
이러한 접근 제어자는 속성뿐 아니라 메서드에도 사용이 가능합니다.
클래스 사용 패턴
class UserA {
public first: string;
protected last: string;
private age: number;
constructor(first: string, last: string, age: number) {
this.first = first;
this.last = last;
this.age = age;
}
private getAge() {
return `${this.first} ${this.last} is ${this.age}`;
}
}
클래스 body 부분에서 속성에 대한 타입과 접근 제어자가 명시되어 있으며, constructor 함수의 매개 변수에서도 각각의 매개 변수의 타입이 명시되어 있고, 함수 내부에서 각각의 속성에 매개 변수를 할당하고 있습니다. 이렇게 같은 이름을 반복한 구조가 보기 좋지는 않기 때문에 아래와 같이 클래스를 수정해줄 수 있습니다.
class UserA {
constructor(public first: string, public last: string, public age: number) {}
private getAge() {
return `${this.first} ${this.last} is ${this.age}`;
}
}
클래스 body 부분에서 속성에 대한 타입과 설정한 접근제어자를 제거하고 매개 변수가 있는 부분에서 접근 제어자 설정을 해줍니다.
이때 public이 생략 가능한 영역은 클래스 body 부분이기 때문에 매개 변수에서 접근 제어자를 설정할 경우 public 생략 없이 설정해줘야 합니다.
이렇게 매개 변수에서 속성에 대한 접근 제어자 설정과 타입을 명시해주게 되면 this 키워드를 사용하여 해당 속성에 매개 변수를 할당하지 않고도 속성 사용이 가능해지게 됩니다.
'TypeScript' 카테고리의 다른 글
패키지의 타입 선언 (0) | 2023.01.03 |
---|---|
제네릭 (Generic) - Updated keyof 제약 조건 (0) | 2023.01.03 |
함수 (0) | 2023.01.02 |
타입 별칭(Alias) (0) | 2023.01.02 |
인터페이스 (Interface) (2) | 2023.01.02 |