본문 바로가기
타입스크립트

타입스크립트6. 객체지향 프로그래밍

by 혀닙 2022. 5. 16.

목차

  1. 클래스(추상 클래스, 추상메서드)
  2. interfaces와 type
  3. interface와 type의 비교
  4. 인터페이스 사용해서 클래스가 특정 모양을 따르도록 하기

 

 


 

 

1. 클래스

class Player {
	constructor(
    	private firstName: string,
        private lastName: string,
        public nickname: string
    ){}
}

const son = new Player('heungmin','son','쏘니');

son.firstName	// 에러 발생.속성값 firstName은 private하며 'Player' 클래스 내부에서만 접근 가능함

 

 

 

1-1. 추상클래스란?

  • 다른 클래스가 상속받을 수 있는 클래스
  • 직접 새로운 인스턴스를 생성할 수는 없는 클래스
  • 자바스크립트로 컴파일됨( JS에서는 일반 클래스로 변경됨. 즉, 파일크기가 좀 더 커지고 추가 클래스가 생성됨)

 

1-2. 추상클래스를 사용하는 이유?

  • 다른 클래스들이 표준화된 모양과 속성 그리고 표준화된 메서드를 갖도록 해주는 청사진을 만들기 위해 사용
  • 추상클래스를 다른 클래스들이 특정 모양을 따르도록 하기 위한 용도로 쓴다면 추상 클래스보다는 인스턴스 사용을 추천
  • (인터페이스의 경우 타입스크립트에 의해 보호는 되지만, 자바스크립으로 컴파일 되지 않음)

 

 

abstract class User {	// 다른 클래스에게 상속할 수 있지만 직접 새로운 인스턴스 생성은 불가한 클래스 
	constructor(
    	private firstName: string,	// 접근제어자, 속성명: 데이터 유형
        private lastName: string,
        public nickname: string
    ){}
        getFullName(){		// 추상 클래스 안에 있는 메소드
        	return `${this.firstName} ${this.lastName}`	// 메소드의 구현(implementation)
        }
}

class Player extends User{
}


const son = new Player('heungmin','son','쏘니');
sont.getfullName()

 

 

1-3. 추상 메소드

  • 추상 클래스 안에서 생성되지만
  • 메서드가 구현되어서는 안되며,( =코드가 없는)
  • 코드블럭 내부에는 메소드의 call signature만 작성되어야 함
  • 추상 클래스를 상속받는 모든 것들이 구현 해야 하는 메소드

 

추상 메소드가 있는 경우, 추상 클래스를 상속받는 클래스에서는 반드시 추상 메소드를 구현해야 함

(즉, 추상 클래스 내부에 콜 시그니쳐 작성, 상속받는 클래스에서 코드 작성)

 

 

 

1-4. 필드 접근 제어자(필드의 보호 등급)

  • private: 인스턴스 외부 및 자식 클래스에서 접근 불가
  • protected: 인스턴스 외부에서는 접근 불가하나 자식 클래스에서는 접근 가능
  • public: 인스턴스 외부 및 자식 클래스에서 접근 가능(디폴트)

 

 

 

1-5. 객체의 키값에 데이터 유형 지정

type Words1 = {
	[key: number]: string	// Words 타입이 number 만을 속성으로 가지는 객체
}

let dict1 : Words1 = {
	1: "food",
    2: "",
    3: ""
}


type Words2 = {
	[key: string]: string	// Words 타입이 string 만을 속성으로 가지는 객체
}

let dict2 : Words2 = {
	"potato": "food",
    "carrot": "food",
}

 

 

1-6. 해시맵 생성

type Words = {
	[key: string]: string
}

class Dict {
	private words: Words
    constructor(){
    	this.words = {}
    }
    add(word: Word){	// 클래스를 타입으로 사용
    	if( this.words[ word.term ] === undefined ){
        	this.words[ word.term ] = word.def;
        }
    }
    delete(word: Word){
    	if(this.words[ word.term ] ){
        	delete this.words[ word.term ] = undefined;
        }
    }
    update(word: Word) {
    	if ( this.words [word.term ] ){
        	this.words[ word.term ] = word.def;
        }
    }
    def(term:string){
    	return this.words[term]
    }
}

class Word {
	constructor(
    	public term: string,
        public def: string
    )
}

const kimchi = new Word('kimchi', '한국 음식');

const dict = new Dick()
dict.add(kimchi);

 

 

1-7. static 메소드

class Dict {
	private words: Words
    constructor() {
    }
	static hello() {
    	return 'hello'
    }
}

 

 

객체의 모양을 특정하는 두 가지 방법

  • 타입
  • 인터페이스

 

2. type과 interface

2-1. type 이란?

(1) 타입 스크립트에게 객체의 모양을 설명해줄 수 있음

type Player = {
	nickname: string,
    healthBar: number
}

const son: Player = {
	nickname: 'sonny',
    healthBar: 10
}

 

 

2. 클래스의 데이터 유형을 선언

type Food = string; 
const kimchi: Food = 'delecious'


type Friends = Array<string>	// type Friends가 string의 배열이라는 것을 선언

 

 

3. 타입을 concrete 유형의 특정 값으로 제한

type Team = 'red' | 'blue' | 'yellow'

type Player = {
	nickname: string,
    team: Team;
}

const son: Player = {
	nickname: 'son',
    team: 'red'	// 'red' 또는 'blue' 또는 'yellow' 중 한가지의 값만 사용 가능
}

 

 

2-2. 인터페이스란?

  • 오직 객체(object)의 모양을 특정
  • 자바스크립트로 컴파일 되지 않음
  • 즉, 추상 클래스와 비슷한 보호를 제공하지만 자바스크립트 파일에서 보이지 않음

 

type Team = 'red' | 'blue' | 'yellow'


interface Player{	// 작성된 인터페이스와
	nickname: string,
    team: Team
}


type Player = {		//작성된 타입의 역할은 완전 같다.
	nickname: string,
    team: Team
}

 

 

 

 

 

3. 타입과 인터페이스의 차이점

3-1. 인터페이스/타입의 상속

(1) 인터페이스의 상속

interface User {
	name:string
}


interface Player extends User {	// 문법 구조가 객체지향 프로그램과 비슷하다
}

const son: Player = {
	name: 'son'
}

 

(2) 타입의 상속

type User = {
	name: string
}


type Player = User & {	// & 연산자 사용
}

const son: Player = {
	name: 'son'
}

 

 

 

3-2. 인터페이스의 속성 축적

interface User {
	name: string
}

interface User {
	lastName: string
}

interface User {
	health: number
}

const son: User = {
	name: 'son',
    lasName: 'heungmin',
    number: 7
}

 

 

3-3. 타입과 인터페이스 비교

타입(type) 인터페이스(interface)
용도가 매우 다양 클래스나 객체의 모양을 특정할 때 사용
클래스의 데이터 유형 선언 문법이 객체 지향 프로그램과 비슷
타입 alias 생성 가능 속성의 축적 가능 (extendable)
타입을 concrete 유형의 특정 값으로 제한 가능  

 

 

 

 

4. 인터페이스 사용 시, 클래스가 특정 형태를 따르도록 강제하기

추상클래스를 인터페이스로 바꿔보자

interface User{
	firstName: string,
    lastName: string,
    sayHi(name:string): string,
    fullname(): string
}

interface Human {
	health: number
}

class Player implements User, Human{	//Player가 User와 Human 두개의 인터페이스를 상속받음
	constructor(
        private firstName: string,	// 인터페이스 상속 시는 속성에 private 적용 불가
        private lastName: string
    ){}
    fullName(){
    	return `${this.firstName} ${this.lastName}`
    }
    sayHi(name:string){
    	return `Hello ${name}. My name is ${this.fullName()}`
    }
}


// 아래와 같은 방식으로 인터페이스도 타입으로 사용 가능하다
function makeUser(user: Player){	// 함수의 인자값에 인터페이스 작성해서 객체의 모양 지정
	return 'hi'
}

makeUser({
	firstName: 'son',
    lastName: 'heungmin',
    fullName() => 'son'
    sayHi(name) => 'string'
})

 

 

 

로컬 API와 동일한 형태를 따르되 제네릭 사용

interface SStorage<T> {
	[key:string] : T
}


class LocalStorage<T>{
	private storage: SStorage<T> = {}
    set(key:string,value:T){
    	this.storage[key] = value;
    		//API 디자인의 구현
    }
    remove(key:string){
        delete this.storage[key]
    }
    get(key:string):T {
        return this.stoarge[key]
    }
    clear(){
    	this.storage = {}
    }
}


const stringsStorage = new LocalStorage<string>()	// TS가 제네릭을 바탕으로 콜 시그니쳐 생성해줌
stringsStorage.get('key')	// string
stringsStorage.set('hello','how are you?')


const booleansStorage = new LocalStorage<boolean>()
booleansStorage.get('key')	// boolean
booleansStorage.set('hello',true)

 

댓글