이 글은 TypeScript : 선언 (1편) 의 다음 편입니다.
class는 이미 ES6에 추가된 JavaScript의 문법이다. 그러나 TypeScript에서 몇가지 추가된 문법이 존재한다. ES6의 class의 특징과 TypeScript에는 어떤 것을 할 수 있는지 알아보자.
class(클래스)란, 객체 지향 프로그래밍을 하기 위한 문법이다. 객체 지향 프로그래밍은 모든 데이터를 객체로 바라보며, 객체의 상태와 행동으로 구분지어 개발한다.
우리는 class에서 객체의 상태와 행동을 정의할 수 있기 때문에 객체 지향 프로그래밍에서 class는 필수적인 문법이다.
인스턴스화
라고 하며, 이렇게 선언된 클래스 타입의 객체를 인스턴스
라고 한다.new
키워드를 통해 인스턴스를 생성한다.메소드
로 정의한다. 필드
로 정의한다.constructor(생성자)
라고 한다.// 기존 ES6
class Developer {
//인스턴스 변수 초기화 메소드, contructor
constructor(skill, ability) {
this.skill = skill;
this.ability = ability;
}
//클래스의 행동을 정의하는, 메소드
getSkill() {
return this.skill;
}
getAbility() {
return this.ability;
}
}
const developer = new Developer('TypeScript', 10);
developer.getSkill(); // "TypeScript"
developer.getAbility(); // 10
TypeScript에서는 ES6와 달리, contructor 메소드에서 받은 파라미터의 데이터 타입을 지정해 주어야 한다.
// TypeScript
class Developer {
//클래스의 상태를 기억하는, 필드
skill: string; // 멤버 변수
ability: number; // 멤버 변수
// 데이터 타입 지정하지 않으면, Error !
constructor(skill: string, ability: number) {
this.skill = skill;
this.ability = ability;
}
//...
}
class 내의 멤버 변수들은 public
이 default이기 때문에 위의 class 밖에서 누가나 접근할 수 있다. TypeScript에서는 이런 문제를 방지하기 위해 접근 제어자를 추가했다.
// 기존 ES6
class Developer {
skill: string;
//...
}
const developer = new Developer('TypeScript');
console.log(developer.skill); // 'TypeScript'
멤버변수의 default 값인 constructor 초기화 과정에서 public 키워드를 사용하면 코드를 줄일 수 있다.
// TypeScript
class Developer {
// 멤버 변수 선언 과정 생략...
constructor(public skill: string, public ability: number) {
this.skill = skill;
this.ability = ability;
}
//...
}
멤버 변수를 private으로 선언하게 되면 class 외부에서 접근하는 것을 막을 수 있다. private으로 선언된 멤버 변수들은 class 내에서만 사용할 수 있다. (그러나 TS에서 JS로 번역되는 과정에서 모두 public으로 바뀌는게 함정..)
// TypeScript
class Developer {
constructor(private skill: string, private ability: number) {
this.skill = skill;
this.ability = ability;
}
//...
}
const developer = new Developer('TypeScript', 10);
console.log(developer.skill); // Error !
객체 지향 프로그래밍에서는 상위 객체를 상속 받아 사용할 수 있다. 상속을 하기 위해서는 extends
키워드와 impements
키워드를 사용할 수 있다.
extends
: 상위 객체를 '상속'받아 상위 객체의 필드와 메소드를 모두 사용할 수 있다.
implements
: 상위 객체(interface)를 구현하라는 의미이다. (오버라이드)
class
-> class
상속에 사용된다.interface
-> interface
상속에 사용된다.class Dev extends Person, Animal
)super()
메소드를 호출해주어야한다./*** class -> class 상속 ***/
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
getName() {
console.log(this.name);
}
}
//Person 객체의 필드와 메소드를 모두 사용할 수 있다.
class Developer extends Person {
constructor(name: string) {
super(name); //패생 클래스에서 contructor를 정의하려면 super()를 꼭 호출해야한다.
}
}
const developer = new Developer('jbee');
developer.getName();
/*** interface -> interface 상속 ***/
interface Person {
name: string;
age?: number; //없어도 되는 데이터 타입은 ?로 정의한다.
}
interface Developer extends Person {
skills: string[];
}
const designer: Person = {
name: '최준영',
age: 21,
};
const developer: Developer = {
name: '최준영',
skills: ['React', 'TS'],
};
const myTeam: Person[] = [designer, developer];
interface
를 구현하는데 사용된다.오버라이드
해주어야한다.class Son implements Man, Person
)interface Person {
name: string;
getAbility(): string; // 사람이라면, 능력은 반드시 가지고 있어야하며, 반환값은 string이어야 한다.
}
class Developer implements Person {
name: string;
skill: string;
constructor(name: string, skill: string) {
this.name = name;
this.skill = skill;
}
getAbility() {
return this.skill;
}
}
class Designer implements Person {
name: string;
tool: string;
constructor(name: string, tool: string) {
this.name = name;
this.tool = tool;
}
getAbility() {
return this.tool;
}
}
//interface를 배열로 선언도 가능하다.
const myTeam: Person[] = [new Developer('jun', 'TypeScript'), new Designer('anna', 'Figma')];
myTeam.forEach((person) => {
console.log(person.name, person.getAbility());
}); // "jun", "TypeScript", "anna", "Figma"