📢 어렵고 정석적인 개념 설명보다는 저같은 초보자도 이해하기 쉽게 정리하는 것을 원칙으로 포스팅하고 있습니다. 😄
자바스크립트에서의 클래스
const studentA = {
name: 'Shawn',
age: 30,
grade: 'A+'
};
const studentB = {
name: 'Lee',
age: 25,
grade: 'B'
};
...
객체의 형태가 모두 같고, 값만 다른 객체를 여러 개 찍어내야 한다면 위 코드처럼 일일이 객체를 하나하나 생성하는 것은 어쩌면 매우 비효율적인 방법일 수 있다. 이렇게 같은 형식의 객체들을 찍어내기 위해서는 모양틀이 필요한데, 그 역할을 해주는 게 바로 클래스이다.
class Student {
// 필드
name;
age;
grade;
// 생성자
construct(name, age, grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
// 메서드
sayHi() {
console.log(`My name is ${this.name}`);
}
}
const studentA = new Student('Shawn', 30, 'A+');
const studentB = new Student('Lee', 25, 'B');
객체의 key값이면서 생성자의 매개변수로 사용될 값을 넣어주는데 이 부분을 필드라고 한다.
다음은 구현 부분인 생성자를 만들어줘야 한다. 생성자에는 필드에 있는 값들을 매개변수로 넣어주고 this를 붙여서 객체의 key에 값을 할당해 준다. 메서드 또한 일반 객체에서처럼 똑같이 선언해 주면 된다.
클래스를 호출할 때는 앞에 new를 붙이고 매개변수에 값을 넣어주면 클래스의 생성자 부분에 작성한 대로 객체가 만들어진다. 참고로, 클래스를 생성할 때는 맨 앞의 문자를 대문자로 표시하는 파스칼 표기법을 사용한다.
타입스크립트에서의 클래스
class Student {
name: string;
age: number;
grade: string;
constructor(name: string, age: number, grade: string) {
this.name = name;
this.age = age;
this.grade = grade;
}
sayHi() {
console.log(`My name is ${this.name}`);
}
}
// 클래스를 타입으로도 쓸 수 있다.
const student: Student = {
name: '',
age: 0,
grade: ''
}
타입스크립트에서 클래스는 생성자 매개변수에 타입을 선언한다는 것 외에는 자바스크립트와 다를 게 없다.
그리고 클래스는 타입으로도 사용할 수 있기 때문에 인터페이스처럼 객체의 타입으로도 사용할 수 있다.
class Employee {
name: string;
age: number;
position: string;
constructor(name: string, age: number, position: string) {
this.name = name;
this.age = age;
this.position = position;
}
}
class Excutive extends Employee {
officeNumber: number;
constructor(name: string, age: number, position: string, officeNumber: number) {
super(name, age, position);
this.officeNumber = officeNumber;
}
}
const excutive = new Excutive('Park', 25, 'Developer', 2);
클래스는 인터페이스처럼 상속을 받을 수도 있다. (타입스크립트뿐만 아니라 바닐라 자바스크립트에서도 가능)
위 코드에서 Excutive 클래스는 Employee 클래스를 상속받았다. 따라서 name, age, position을 필드에 똑같이 적어줄 필요가 없다. 대신, 생성자에서 super()를 이용해 상속받은 클래스의 매개변수를 호출해와야 한다.
class Student {
public name: string; // 모두 사용 가능 (디폴트)
private age: number; // 클래스 내부에서만 접근 가능 & 파생 클래스 접근 불가
protected grade: string; // 클래스 내부에서만 접근 가능 & 파생 클래스 접근 가능
constructor(name: string, age: number, grade: string) {
this.name = name;
this.age = age;
this.grade = grade;
}
}
class BestStudent extends Student {
year: string;
constructor(name: string, age: number, grade: string; year: string) {
super(name, age, grade);
this.year = year;
}
sayHi() {
console.log(`Hi, My name is ${this.age}`); // age는 private라서 Error
console.log(`And My grade is ${this.grade}`); // grade는 protected라서 오류 없음
}
}
let student = new Student('Shawn', 30, 'A+');
student.name = 'Lee';
student.age = 25; // Error! age는 private
student.grade = 'B+'; // Error! grade는 protected
타입스크립트만의 클래스 특징이라면 바로 접근 제어자를 사용할 수 있다는 점이다. 접근 제어자는 해당 값을 클래스 외부에서도 접근이 가능하게 할 건지의 여부를 정하는 문법인데 필드나 생성자의 매개변수 앞에 붙여서 선언해 줄 수 있다.
public은 접근 제어자의 디폴트 값으로 접근 제어자가 생략된 상태라도 사실상 public이 선언되어 있다고 보면 된다. public으로 선언된 값들은 클래스 내부든 외부든 어디에서나 접근이 가능하다.
private은 오로지 클래스의 내부에서만 접근이 가능하며, extends로 상속된 파생 클래스에서 조차도 사용이 불가능하다.
protected는 public과 private의 중간 역할로 클래스 내부에서만 접근이 가능하지만, 파생 클래스에서의 접근은 허용한다.
class Student {
// 필드 생략 가능
construct(public name: string, private age: number) {
// 생성자 내용 생략 가능
};
}
const student = new Student('Shawn', 30);
student.age = 25; // Error! age는 private
접근 제어자를 사용하면 클래스를 조금 더 깔끔하게 선언해 줄 수 있다. 바로 생성자 매개변수에 접근 제어자를 직접적으로 넣어주는 것인데, 이렇게 하면 필드 부분과 생성자의 내용 부분을 생략할 수 있다.
interface Type1 {
name: string;
age: number;
}
class Student implements Type1 {
// implements로 인터페이스를 받아올 때 접근 제어자는 only public
constructor (public name: string, public age: number) {}
}
const student = new Student('Shawn', 30);
클래스는 인터페이스를 가져올 수도 있는데, 상속의 개념보다는 인터페이스의 구조를 따라서 구현한다는 의미로 인터페이스를 설계도 삼아 구현한다고 볼 수 있다. implements를 사용할 때 주의할 점은 접근 제어자가 오로지 public만 가능하다는 점이다. 이러한 방식은 정말 정교한 프로그래밍을 할 때나 사용되며 일반적으로는 잘 사용되는 방식은 아니다.
1. 클래스 구조 : 필드, 생성자(constructor)
2. extends를 이용해서 클래스끼리 상속도 가능.
3. 필드에는 생성자 매개변수에 사용될 값을 넣고, 생성자에는 this를 이용해서 객체를 구현해 준다.
4. 타입스크립트에서 클래스는 접근 제어자를 사용할 수 있다.
5. public은 모두 접근 가능, private는 클래스 내부만/파생 클래스 X, protected는 클래스 내부만/파생 클래스 O
6. class A implements B로 클래스 생성 시에 인터페이스 구조를 가져올 수 있다.
7. implements를 이용해서 인터페이스를 구현할 때는 접근 제어자가 public만 가능.
'TypeScript' 카테고리의 다른 글
[TypeScript] 타입을 조작하는 4가지 방법 (인덱스, keyof, 맵드) (0) | 2023.08.04 |
---|---|
[TypeScript] 타입 변수로 타입을 받아오는 제네릭 (0) | 2023.08.01 |
[TypeScript] 객체의 타입을 정의할 때 쓰면 좋은 interface (0) | 2023.07.28 |
[TypeScript] 타입스크립트 함수 타입 정의 방법 (0) | 2023.07.25 |
[TypeScript] 타입 단언으로 변수에 타입 부여해주기 (vs 타입 선언) (0) | 2023.07.23 |