반응형
TS 의 클래스
- 타입스크립트에서는 클래스의 필드를 선언할 때 타입 주석으로 타입을 함께 정의해주어야 한다.
- 그렇지 않으면 함수 매개변수와 동일하게 암시적 any 타입으로 추론되는데
엄격한 타입 검사 모드(strict 옵션이 true로 설정되어 있을 경우)일 때에는 오류가 발생하게 된다. - 추가로 생성자에서 각 필드의 값을 초기화 하지 않을 경우 초기값도 함께 명시해주어야 한다.
class Employee {
// 필드
name: string = "";
age: number = 0;
position: string = "";
// 메서드
work() {
console.log("일함");
}
}
만약 다음과 같이 생성자 함수에서 필드의 값들을 잘 초기화 해 준다면 필드 선언시의 초기값은 생략해도 된다.
class Employee {
// 필드
name: string = "";
age: number = 0;
position: string = "";
// 생성자
constructor(name: string, age: number, position: string) {
this.name = name;
this.age = age;
this.position = position;
}
// 메서드
work() {
console.log("일함");
}
}
- 이때 만약 이 클래스가 생성하는 객체의 특정 프로퍼티를 선택적 프로퍼티로 만들고 싶다면
다음과 같이 필드의 이름 뒤에 물음표를 붙여주면 된다.
class Employee {
// 필드
name: string = "";
age: number = 0;
position?: string = "";
// 생성자
constructor(name: string, age: number, position: string) {
this.name = name;
this.age = age;
this.position = position;
}
// 메서드
work() {
console.log("일함");
}
}
클래스는 타입이다.
타입스크립트의 클래스는 타입으로도 사용할 수 있다.
클래스를 타입으로 사용하면 해당 클래스가 생성하는 객체의 타입과 동일한 타입이 된다.
class Employee {
(...)
}
const employeeC: Employee = {
name: "",
age: 0,
position: "",
work() {},
};
- 변수 employeeC의 타입을 Employee 클래스로 정의했다.
- 이 변수는 name, age, position 프로퍼티와 work 메서드를 갖는 객체 타입으로 정의된다.
상속
타입스크립트에서 클래스의 상속을 이용할 때 파생 클래스(확장하는 클래스)에서 생성자를 정의 했다면
반드시 super 메서드를 호출해 슈퍼 클래스(확장되는 클래스)의 생성자를 호출해야 하며
호출 위치는 생성자의 최상단 이어야만 한다.
class ExecutiveOfficer extends Employee {
officeNumber: number;
constructor(
name: string,
age: number,
position: string,
officeNumber: number
) {
super(name, age, position);
this.officeNumber = officeNumber;
}
}
접근 제어자
접근 제어자(Access Modifier)는 타입스크립트에서만 제공되는 기능으로
클래스의 특정 필드나 메서드를 접근할 수 있는 범위를 설정하는 기능이다.
클래스의 특정 필드나 메서드를 접근할 수 있는 범위를 설정하는 기능이다.
타입스크립트에서는 다음과 같은 3개의 접근 제어자를 사용할 수 있다.
- public : 모든 범위에서 접근 가능
- private : 클래스 내부에서만 접근 가능
- proteced : 클래스 내부 또는 파생 클래스 내부에서만 접근 가능
public
- 어디서든지 이 프로퍼티에 접근할 수 있음을 의미
class Employee {
// 필드
name: string; // 자동으로 public
age: number; // 자동으로 public
position: string; // 자동으로 public
// 생성자
constructor(name: string, age: number, position: string) {
this.name = name;
this.age = age;
this.position = position;
}
// 메서드
work() {
console.log("일함");
}
}
const employee = new Employee("이재민", 30, "devloper");
employee.name = "홍길동";
employee.age = 30;
employee.position = "디자이너";
private
- 제한된, 사적인 이라는 뜻으로 특정 필드나 메서드의 접근 제어자를 private으로 설정하면
클래스 내부에서만 이 필드에 접근할 수 있게 된다.
class Employee {
// 필드
private name: string; // private 접근 제어자 설정
public age: number;
public position: string;
...
// 메서드
work() {
console.log(`${this.name}이 일함`); // 여기서는 접근 가능
}
}
const employee = new Employee("이재민", 30, "devloper");
employee.name = "홍길동"; // ❌ 오류
employee.age = 30;
employee.position = "디자이너";
protected
- private과 public의 중간으로 클래스 외부에서는 접근이 안되지만
클래스 내부와 파생 클래스에서 접근이 가능하도록 설정하는 접근 제어자이다.
class Employee {
// 필드
private name: string; // private 접근 제어자 설정
protected age: number;
public position: string;
...
// 메서드
work() {
console.log(`${this.name}이 일함`); // 여기서는 접근 가능
}
}
class ExecutiveOfficer extends Employee {
// 메서드
func() {
this.name; // ❌ 오류
this.age; // ✅ 가능
}
}
const employee = new Employee("이재민", 30, "devloper");
employee.name = "홍길동"; // ❌ 오류
employee.age = 30; // ❌ 오류
employee.position = "디자이너";
필드 생략하기
- 접근 제어자는 다음과 같이 생성자의 매개변수에도 설정할 수 있다.
class Employee {
// 필드
private name: string; // ❌
protected age: number; // ❌
public position: string; // ❌
// 생성자
constructor(
private name: string,
protected age: number,
public position: string
) {
this.name = name;
this.age = age;
this.position = position;
}
// 메서드
work() {
console.log(`${this.name} 일함`);
}
}
- 그러나 생성자에 접근 제어자를 설정하면 동일한 이름의 필드를 선언하지 못하게 된다.
- 그 이유는 생성자 매개변수에 name, age, position 처럼 접근 제어자가 설정되면 자동으로 필드도 함께 선언되기 때문이다.
따라서 동일한 이름으로 필드를 중복 선언할 수 없게 된다. - 다음과 같이 중복된 필드 선언을 모두 제거해 주어야 한다.
class Employee {
// 생성자
constructor(
private name: string,
protected age: number,
public position: string
) {}
// 메서드
work() {
console.log(`${this.name} 일함`);
}
}
- 타입스크립트에서 클래스를 사용할 때에는 보통 생성자 매개변수에 접근 제어자를 설정하여
필드 선언과 생성자 내부 코드를 생략하는것이 훨씬 간결하고 빠르게 코드를 작성할 수 있어 좋다.
인터페이스를 구현하는 클래스
타입스크립트의 인터페이스는 클래스의 설계도 역할을 할 수 있다.
다음과 같이 인터페이스를 이용해 클래스에 어떤 필드들이 존재하고, 어떤 메서드가 존재하는지 정의할 수 있다.
/**
* 인터페이스와 클래스
*/
interface CharacterInterface {
name: string;
moveSpeed: number;
move(): void;
}
class Character implements CharacterInterface {
constructor(
public name: string,
public moveSpeed: number,
private extra: string
) {}
move(): void {
console.log(`${this.moveSpeed} 속도로 이동!`);
}
}
- 인터페이스 CharacterInterface는 name, moveSpeed 프로퍼티와 move 메서드를 갖는 객체 타입을 정의한다.
- 인터페이스를 클래스에서 implements 키워드와 함께 사용하면
이 클래스가 생성하는 객체는 모두 이 인터페이스 타입을 만족하도록 클래스를 구현해야 한다
반응형
'Typescript' 카테고리의 다른 글
Typescript | 제네릭 인터페이스, 제네릭 타입 별칭, 제네릭 클래스, Promise와 제네릭 (1) | 2024.11.03 |
---|---|
Typescript | 제네릭, 타입 변수 응용, map, forEach 메서드 타입 정의 (1) | 2024.11.03 |
Typescript | 인터페이스, 확장, 선언 합치기 (0) | 2024.11.02 |
Typescript | 함수 오버로딩, 사용자 정의 타입가드 (0) | 2024.11.02 |
Typescript | 함수 타입, 함수 타입 표현식과 호출 시그니처, 호환성 (0) | 2024.11.02 |