- 클래스는 다른 프로그래밍 언어에서도 존재하는 문법입니다. JavaScript에서는 ES2015의 새로운 문법입니다.
- TypeScript에서의 클래스 기능은 C#에서 유래된 것이 많습니다.
- JS에서 제공하는 클래스와 TS에서 제공하는 클래스가 상이합니다
- 일부 기능은 TS에서만 존재하는 고유 문법으로 컴파일 후에 사라집니다.
필드란 일종의 속성으로, public으로 사용 가능합니다.
class Person {
name: string;
age: number;
readonly location: string = "Korea";
}
아래와 같이 자바스크립트로 컴파일이 됩니다.
생성자
- 생성자는 클래스가 만들어질 때 반드시 필요하며 초기화를 담당합니다.
- 클래스가 인스턴스화될 때 생성되는 순간에 인스턴스를 필요한 것들을 세팅하고 초기화 합니다.
인스턴스
- 클래스에서 파생된 고유한 것으로, 실제로 생성된 후 메모리에 올라갑니다.
/**
* Class
*/
class Person {
//필드
name: string;
age: number;
readonly location: string = "Korea";
//생성자
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
//인스턴스
const p1 = new Person('Jang', 99);
const p2 = new Person('Poco', 100);
console.log(p1)
console.log(p2)
class Person {
//필드
name: string;
age: number;
readonly location: string = "Korea";
//생성자
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
//메서드
introduce(): string {
return `${this.name}의 나이는 ${this.age} 입니다.`
}
}
//인스턴스
const p1 = new Person('Jang', 99);
const p2 = new Person('Poco', 100);
console.log(p1.introduce())
console.log(p2.introduce())
- 필드에 접근할 권한을 가진 제어자
- getter O / setter X => 속성은 자동으로 읽기 전용
- setter 매개변수의 타입 X / getter의 반환 타입에서 추론
- private 속성은 .연산자로 접근할 수 없다.
Getter & Setter는 필드에 접근할 수 있는 필드접근자로 clas에서 필드는 아래와 같이 큰 어려움 없이 접근할 수 있습니다.
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
const p = new Person('Roh', 93)
//이처럼 필드에 쉽게 접근할 수 있습니다.
console.log(p.age)
console.log(p.name)
또한 클래스 필드를 이용하면 필드에 접근하는 것을 제어할 수 있습니다.
예시로 private속성을 보도록 하겠습니다.
class Person {
name: string;
//_ 은 숨겨진 속성을 사용할 때 사용하는 컨벤션입니다.
private _age: number;
constructor(name: string, age: number) {
this.name = name
this._age = age
}
}
위와 같이 private속성이 사용된 부분은 에러가 발생을 하게 됩니다.
이렇게 내부적으로 숨겨진 것을 접근하기 위해 사용되는 것이 바로 getter입니다,
이렇게 getter을 설정해주면 어디서 어떻게 접근을 하든 나이를 보여주는 부분을 바꿀 수 있게 됩니다.
마찬가지로 setter을 사용해 들어오는 정보를 제한 할 수도 있습니다.
extends는 객체지향에서 널리 알려진 개념입니다.
과연 extends키워드를 상속으로 바라볼지? 확장으로 바라볼지 고민해보는 것이 좋습니다.
class 기본 {
result() {
return 'Base'
}
}
class 파생 extends 기본 {
result() {
return 'Derived'
}
}
const de = new 파생()
console.log(de.result())
class Animal {
name: string
constructor(name: string) {
this.name = name
}
sayName() {
return `동물의 이름은 ${this.name}`
}
}
//파생클래스
class Person extends Animal {
constructor(name: string) {
//animal의 생성자를 쓰고 싶을 때 super을 사용할 수 있습니다
super(name)
}
sayName() {
//this.name은 Person에 존재하지 않고 Animal에 존재를 합니다.
return `${super.sayName()} 사람의 이름은 ${this.name}`
}
}
this는 인스턴스를 가르키기 때문에 결국 생성된 인스턴스에서 재활용할 수 있습니다.
제어자 | 설명 |
---|---|
public | 어디서나 접근 가능 (기본값) |
protected | 해당 클래스와 서브클래스에서만 접근 가능 |
private | 해당 클래스에서만 접근 가능 |
class Person {
public name: string
private age: number
protected gender: 'M' | 'F'
constructor(name: string, age: number, gender: 'M' | 'F') {
this.name = name
this.age = age
this.gender = gender
}
sayName() {
return `이름은 ${this.name} 입니다`
}
protected sayAge() {
return `나이는 ${this.age}`
}
private sayGender() {
return `성별 타입은 ${this.gender}`
}
}
class Me extends Person {
constructor(name: string, age: number, gender: 'M' | 'F') {
super(name, age, gender)
}
sayInfo() {
return `${super.sayGender()} ${super.sayAge()} ${super.sayName()}`
}
}
readonly는 타입스크립트에서 제공되는 기능입니다. 일반적인 속성에 프리픽스로 readonly만 붙이면 쉽게 사용이 가능합니다.
자바스크립트에서는 수정할 수 있는 접근제어자가 있습니다. 이를 통해 인스턴스의 데이터를 쉽게 수정할 수 있습니다.
하지만 readonly를 통해 수정할 수 없도록 막아줄 수 있습니다. 이를 통해 안전한 클래스를 만들수 있습니다.
abstract
를 선언한 클래스로 직접 인스턴스화 될 수 없는 클래스이다.extends
후 파생된 클래스를 인스턴스화하도록 유도한다.abstract
선언한 메서드는 파생된 클래스에서 메서드를 구현해야한다.class Animal {
//선언된 메서드
hello()
//구현된 메서드
run(){
return this.hello() + 'run'
}
}
//추상클래스는 직접 인스턴스가 될 수 없습니다.
//const animal = new Animal()
//하지만 `extends` 후 파생된 클래스를 인스턴스화하도록 유도합니다.
class Person extends Animal {
}
const person = new Person
만약, extends
후 파생된 클래스가 모두다 hello()라는 메서드를 포함하도록 강제시키고 싶다면 어떻게해야할까요?
abstract class Animal {
// 선언된 메서드
abstract hello(): string
// 구현된 메서드
run() {
return this.hello() + ' run'
}
}
class Person extends Animal {
//hello()가 포함되어 있지 않기 때문에 에러가 발생합니다.
}
class Dog extends Animal {
hello() {
return 'Dog'
}
}
class Person {
//필드
public name: string,
private age: number,
protected gender: 'M' | 'F'
//생성자매개변수
constructor(name: string, age: number, gender: 'M' | 'F') {
this.name = name
this.age = age
this.gender = gender
}
}
타입스트립트에서 필드를 한번 만들고 생성자매개변수를 한번 더 만드는 과정이 너무 귀찮게 느껴질 수 있습니다.
public name: string,
private age: number,
protected gender: 'M' | 'F'
또한 위와 같은 접근제어자/접근제어자에 대한 필드네임/ 필드네임에 대한 타입을 Parameter Properties을 통해 한번에 생성할 수 있습니다.
위의 녀석들을 constructor의 생성자매개변수에 넣어 정의를 하는 것입니다.
class Person {
constructor(public name: string, private age: number, protected gender: 'M' | 'F') {
this.name = name
this.age = age
this.gender = gender
}
}
또한 아래와 같이 생략도 가능합니다.
class Person {
constructor(
public name: string,
private age: number,
protected gender: 'M' | 'F'
) {//이부분을 생략
}
}
class Animail {
run(){
return 'Animal이 달린다'
}
}
class Dog extends Animal {
}
class Person extends Animal {
}
const p = new Person()
console.log(p.run())
타입스크립트든, 자바스크립트에서든 파생된 클래스에서는 기본 베이스나 필드에 접근할 수 있는 장점이 있습니다.
class Animail {
run(){
return 'Animal이 달린다'
}
}
class Dog extends Animal {
run(){
return 'Dog 달린다'
}
}
class Person extends Animal {
run(){
return 'Person 달린다'
}
}
const p = new Person()
console.log(p.run())
위와 같이 Animal, Dog, Person모두 run이라는 메소드를 가지고 있을 때 확장된 Person이라는 클래스에서 run()메서드를 덮어써야하는 경우, 메서드 오버라이딩을 공유할 수 있습니다.