[타입스크립트로 블록체인 만들기] #4. Classes and Interfaces

min5x5·2023년 11월 2일
post-thumbnail

#4.0 Classes

constructor를 작성하면, js로 컴파일 후 자동으로 this. 가 생성된다.
private, public은 js에 없지만 ts에서 사용하면 컴파일 전에 확인 가능하다.

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

const nico = new Player("nico", "las", "니꼬")

Abstract Class
추상클래스는 다른 클래스가 상속받을 수 있는 클래스다.
직접 새로운 인스턴스를 만들 수 없다.
다른 곳에서만 상속받을 수 있는 클래스다.

private: property들은 당연히 인스턴스 밖에서 접근할 수 없고, 다른 자식 클래스에서도 접근할 수 없다.
protected: property들은 인스턴스 밖에서는 접근할 수 없고, 다른 자식 클래스에서는 접근할 수 있다.

  • 메소드: 클래스 안에 존재하는 함수
abstract class User {
	constructor(
    	private firstName: string,
        private lastName: string,
        public nickName: string
    ) {}
    
    abstract getNickName(): void
    
    getFullName() {
    	return `${this.firstName} ${this.lastName}`
    }
}

class Player extends User {
	getNickName() {
    	console.log
	}
}

const nico = new Player("nico", "las", "니꼬")

#4.1 Recap

abstract method
argument를 받을 경우 이름, 타입, 함수의 리턴타입을 정의한다.
abstract class를 상속받는 클래스에서 abstract method를 구현해주어야 한다.

public, private, protected
public: 기본값, 어디서든 접근가능
private: 해당 클래스에서만 접근가능
protected: 해당 클래스, 자식클래스에서 접근가능

type Words = {
	[key: string]: string // key와 value 값이 string이어야 한다.
}
class Dict {
	private words: Words
    constructor(){
    	this.words = {}
    }
    add(word: Word) { // class를 이용해서 type로 쓸 수 있다!!!!
    	if(this.words[word.term] === undefined){
        	this.words[word.term] = word.def
        }
    }
    def(term: string){
    	return this.words[term];
    }
}

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

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

const dict = new Dict();

dict.add(kimchi);
dict.def("kimchi");

#4.2 Interfaces

interface는 object의 모양을 결정할 때만 사용한다.
type를 사용할 수 있지만 type는 object 뿐만 아니라 다른 값을 결정할 때도 사용할 수 있다.

interface를 사용하는 게 클래스를 사용하는 느낌과 비슷해서 더 쉽다.

type Team = "red" | "blue" | "yellow"
type Health = 1 | 5 | 10

interface Player {
	nickname: string,
    team: Team,
    health: Health
}

type Player = {
	nickname: string,
    team: Team,
    health: Health
}

const nico: Player = {
	nickname: "nico",
    team: "yellow",
    health: 10
}
interface User {
	name: string
}

interface Player extends User { // User를 상속받을 수 있다.
}

const nico: Player = {
	name: "nico"
}

// type를 사용한다면 다음과 같이 쓸 수 있다.
type User = {
	name: string
}

type Player = User & { 
}

const nico: Player = {
	name: "nico"
}

interface는 객체 지향 프로그래밍의 개념을 활용해서 디자인되었다.
각각 만들어도 타입스크립트가 알아서 하나로 합쳐준다. type는 안됨.

interface User {
	name: string
}

interface User {
	lastName: string
}

interface User {
	health: number
}

#4.3 Interfaces part2

interface와 type는 상속하는 방법이 다르다.

abstract class는 상속받는 다른 클래스가 가질 property와 method를 지정한다.

// 다른 클래스가 따라야 할 청사진(설계도)만을 제시했을 뿐이다.
// User class를 상속한다면 sayHi, fullName을 구현해야 한다.
// abstract class가 js에서는 일반적인 클래스로 바뀐다.
abstract class User {
	 constructor(
     	protected firstName: string,
        protected lastName: string
    ) {}
    abstract sayHi(name: string): string
    abstract fullName(): string
}

class Player extends User {
	fullName() {
    	reuturn `${this.firstName} ${this.lastName}`
    }
    sayHi(name: string) {
    	return `Hello ${name} My name is ${this.fullName}`
    }
}
    

interface는 typescript에서만 존재하고, js로 컴파일되지 않기 때문에 존재하지 않는다.
class가 아니지만 class의 모양을 특정할 수 있기 때문에 유용하다!!

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

interface Human {
	health: number,
}
class Player implements User, Human { //2개의 interface를 implement할 수 있다!
	constructor(
    	public firstName: string, //interface에서는 public이 되어야만!
        public lastName: string,
        public health: number,
    ) {}
	fullName() {
    	reuturn `${this.firstName} ${this.lastName}`
    }
    sayHi(name: string) {
    	return `Hello ${name} My name is ${this.fullName}`
    }  
}

#4.4 Recap

type과 interface의 차이점
ts에게 object의 모양과 타입을 알려주는 게 목표라면, type와 interface 둘 다 사용 가능하다. 하지만 둘을 사용해서 할 수 있는 것들이 다르다.

type는 변수명을 중복해서 쓸 수 없고,
interface는 변수명이 중복해서 추가로 사용할 수 있다. 즉, interface 정의를 합칠 수 있다!

// type
type PlayerA = {
	name: string
}
type PlayerAA = PlayerA & {
	lastName: string
}

const playerA: PlayerAA = {
	name: "nico"
    lastName: "xxx"
}


// interface
interface PlayerB {
	name: string
}
interface PlayerB {
	lastName: string
}
interface PlayerB {
	health: number
}
const playerB: PlayerB = {
	name: "nico",
    lastName: "xxx",
    health: 1
}

type, interface 모두 추상 클래스를 대체해서 사용할 수 있다.
클래스나 오브젝트의 모양을 정의하고 싶으면 interface를 사용하고, 다른 경우에는 type를 많이 사용한다.

type PlayerA = {
	firstName: string
}
interface PlayerB {
	firstName: string
}
class User implements PlayerB { // PlayerA를 사용해도 무방
	constructor(
    	public firstName: string
    ) {}
}

#4.5 Polymorphism

T라고 불리는 Generic을 Class로 보내고,
Class는 Generic을 interface로 보낸 뒤에,
interface는 Generic을 이용한다.

LocalStorage API를 따라해보자.

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

class LocalStorage<T> { // T라고 불리는 Generic을 받을 계획이다.
	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>();
// generic을 바탕으로 call signature를 만들어준다.
// typescript가 concrete type으로 바꿔준다!
stringStorage.get("key");
stringStorage.set("hello", "how are you");

const booleanStorage = new LocalStorage<boolean>();
booleanStorage.get("XXX");
booleanStorage.set("hello", true);
profile
삶에 변화를 만드는 개발자

0개의 댓글