Typescript 3
객체 지향 프로그래밍 (Object-Oriented-Programing)
클래스 (Class)
Typescript의 클래스에는 타입과 접근 제한자 등이 추가되었다.
메소드(Method) : 클래스 안에 구현된 함수를 말한다.
인스턴스(Instance) : 클래스로 만들어진 오브젝트를 인스턴스 라고 부른다.
class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
class User {
private name: string; // this로 변수를 참조하기 위해서는 먼저 선언해주어야 한다.
constructor(
private age: number, // 멤버 변수를 자동으로 추가해준다.
name: string
) {
this.name = name; // 이미 선언된 변수를 수정하는 방식
// this.age = age; → this.age 변수가 없어서 에러 발생
}
}
접근 제한자 (Access modifier)
public : 모든 접근을 허용한다. (기본값)
protected : 자신과 자식 클래스에서만 접근이 가능하다.
private : 자신을 제외한 자식 클래스나, 인스턴스에서 접근할 수 없도록 막는다.
| 접근 가능성 | Public | Protected | Private |
|---|---|---|---|
| 클래스 내부 | O | O | O |
| 자식 클래스 내부 | O | O | X |
| 클래스 인스턴스 | O | X | X |
class User {
constructor(public name: string, protected age: number, private id: number) {}
}
class UserA extends User {
constructor(name: string, age: number, id: number) {
super(name, age, id);
console.log(this.name); // 참조 가능
console.log(this.age); // 참조 가능
console.log(this.id); // 참조 불가능
}
}
const a = new UserA('aaa', 20, 393920);
console.log(a.name); // 참조 가능
console.log(a.age); // 참조 불가능
console.log(a.id); // 참조 불가능
정적 속성, 메소드 (Static)
클래스의 인스턴트를 생성하지 않고 속성, 메소드를 사용하기 위해 static 키워드를 사용한다.
class WorldMap {
// 정적 속성
static mapSize: number = 50;
// 정적 메소드
static resizeMap(size: number): void {
this.mapSize = size;
}
}
WorldMap.resizeMap(20);
console.log(WorldMap.mapSize);
추상 클래스 (Abstract class)
클래스를 동일하게 만들어내기 위한 설계도가 추상 클래스이다.
추상 클래스를 상속받은 클래스를 만들어 사용해야 하고, 직접 새로운 인스턴스를 만들지는 못한다.
abstract class User {
constructor(public name: string, protected age: number, private id: number) {}
}
class UserA extends User {}
const a = new UserA('aaa', 20, 393920);
const b = new User('bbb', 20, 148993); // 직접 인스턴스 생성 불가
추상 클래스에 정의된 추상 메소드는 call signiture를 정의하고 몸체는 구현하지 않는다.
추상 메소드는 상속받은 클래스에서 반드시 정의해야 한다.
abstract class User {
constructor(public name: string, protected age: number, private id: number) {}
abstract getUserName(): string;
}
class UserA extends User {
getUserName() {
// 추상 메소드를 정의하지 않으면 에러 발생
return this.name;
}
}
const a = new UserA('aaa', 20, 393920);
클래스 사용 예시
클래스를 이용하여 단어와 정의로 이루어진 사전을 만드는 예시다.
// 오브젝트 타입을 만들 때 key와 value의 타입을 정할 수 있다. → dictonary
type Words = {
// [key의 타입 ('key'가 아닌 어떤 문자가 와도 상관 없음)] : value의 타입
[key: string]: string;
};
// 단어와 정의를 저장하는 사전 클래스
class Dict {
private words: Words = {};
// 클래스를 타입으로 사용할 수 있다.
addWord(word: Word) {
if (this.words[word.term] === undefined) {
// 사전에 단어가 정의되지 않은 경우
this.words[word.term] = word.def;
}
}
getWord(term: string) {
return this.words[term];
}
}
// 사전에 들어가는 단어 클래스
class Word {
constructor(public term: string, public def: string) {}
}
const dict = new Dict();
const Typescript = new Word(
'Typescript',
'TypeScript is JavaScript with syntax for types.'
);
dict.addWord(Typescript);
console.log(dict.getWord('Typescript'));
인터페이스 (Interface)
오브젝트의 형태를 정의하는 목적으로 타입 대신에 사용한다.
모든 인터페이스의 기능은 타입을 사용해도 구현할 수 있다.
type Person = {
name:string,
age:number
}
interface Person {
name:string,
age:number
}
// 위의 두 코드는 같은 기능을 한다.
interface Name = string; // 에러 interface는 오브젝트만 정의할 수 있다.
클래스가 인터페이스를 상속 받아 사용할 수 있다.
인터페이스를 상속 받은 클래스는 private, protected 를 사용하지 못한다.
interface User {
firstName: string;
lastName: string;
fullName(): string;
}
class Player implements User {
constructor(public firstName: string, public lastName: string) {}
fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
타입과 인터페이스의 차이
기존에 타입에 값을 추가하기 위해서는 새로운 타입을 만들어 & 연산자로 타입을 추가해야 한다.
인터페이스는 기존 인터페이스에 추가하거나 상속 받아 확장하여 사용할 수 있다.
// 타입에 갑을 추가하는 방법
type PlayerA = {
name: string;
};
type PlayerAA = PlayerA & {
lastName: string;
};
const a: PlayerAA = {
name: 'a',
lastName: 'A',
};
// 인터페이스에 값을 추가하거나 상속받는 방법
interface PlayerB {
name: string;
}
interface PlayerB {
// 자동으로 인터페이스가 합쳐진다.
firstName: string;
}
interface PlayerBB extends PlayerB {
lastName: string;
}
const b: PlayerBB = {
name: 'b',
firstName: 'B',
lastName: 'B',
};
타입을 여러개 사용하는 경우
|는 or 연산자로 여러개의 타입 중 하나를 의미한다.
&는 and 연산자로 여러개의 타입 모두를 의미한다.
type Status = 'success' | 'fail' | 'error';
const s = 'fail';
const s = 'not fail'; // 타입 에러
type A = { name: string };
type B = A & { age: number };
const b: B = { name: 'bbb', age: 111 };
추상화와 인터페이스의 차이
추상 클래스는 컴파일 시 일반 클래스로 변환된다.
인터페이스는 자바스크립트 코드로 변환되지 않고 사라진다.
추상 클래스를 남기지 않고 클래스의 형태를 정하기만 할 때 인터페이스를 사용한다.
// 추상 클래스를 이용한 방법 (컴파일 시 User 클래스가 남는다.)
abstract class User {
constructor(
public name:string
){}
getName():string
}
class Player extends User {...}
// 인터페이스를 이용한 방법 (컴파일 시 Player 클래스만 남는다.)
interface User {
public name:string,
getName():string
}
class Player implements User {...}
다양성 (Polymorphism)
인터페이스와 클래스에서 제네릭을 적용하는 방법이다.
LocalStorage에서 타입 T를 제네릭으로 받아서 전달한다.
interface SStorage<T> {
[key: string]: T;
}
class LocalStorage<T> {
private storage: SStorage<T> = {};
set(key: string, value: T) {
this.storage[key] = value;
}
remove(key: string) {
delete this.storage[key];
}
get(key: string): T {
return this.storage[key];
}
clear() {
this.storage = {};
}
}
const stringsStorage = new LocalStorage<string>();
stringsStorage.set('1', 'first');
const booleanStorage = new LocalStorage<boolean>();
booleanStorage.set('false', false);
