오늘도 코딩하나

[Typescript] 타입스크립트로 블록체인 만들기_(5) 본문

Typescript/Lecture

[Typescript] 타입스크립트로 블록체인 만들기_(5)

오늘도 코딩하나 2025. 1. 9. 15:08

https://nomadcoders.co/typescript-for-beginners

 

타입스크립트로 블록체인 만들기 – 노마드 코더 Nomad Coders

Typescript for Beginners

nomadcoders.co

 

강의 내용
#4.2 ~ #4.5

 

🤷‍♀️ public이지만 더 이상 변경할 수 없도록 만들 수 없을까?

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

  ⇒ readonly


static

    static : 클래스의 인스턴스가 아니라 클래스 자체에 속하는 메소드

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

class Dict {
    private words:Words
    constructor() {
        this.words = {}
    }
    def(term:string) {
        return this.words[term]
    }

    static hello() {
        return "hello"
    }
}

const dict = new Dict()
dict.def("kimchi")

Dict.hello()
  • def 메소드는 클래스의 인스턴스 메소드로 정의되어 있기 때문에, 인스턴스를 통해서만 호출할 수 있다.
  • hello 메소드클래스 메소드로 정의되어 있기 때문에, 인스턴스를 생성하지 않아도 사용할 수 있다.

🤷‍♀️ type을 특정 값을 가지도록 할 수 없을까?

type Team1 = string
type Team2 = "red" | "blue" | "yellow"
type Health = 1 | 5 | 10

type Player = {
    nickname:string
    team:Team2,
    health: Health
}
const tistory :Player = {
    nickname:"tistory",
    team:"red",
    health:10
}
  • type alias
    : Team1, Team2, Health
  • 특정 값들로만 제한 (리터럴 타입)
    : concrete 타입의 특정 값으로 제한할 수 있다.
    : Team2, Health

 interface

    interface : object의 모양을 설명할 때만 사용할 수 있다.

  ⭐ React.js에서 많이 사용된다!

interface User {
    name:string
}

interface User {
    lastname:string
}

interface User {
    health:number
}

interface Player extends User {

}

const tistory : Player = {
    name:"오늘도",
    lastname:"코딩하나",
    health:10
}
  • property들을 축적시킬 수 있다.
    → interface를 N번 각각 만들기만 하면, Typescript가 알아서 하나로 합쳐주기 때문!
  • 클래스가 property와 메소드를 가지도록 강제할 수 있다.
    → User 인터페이스에 name, lastname, health 3가지의 property를 정의한 후,
         이를 Player 인터페이스가 extends했다.
         Player 인터페이스를 구현하는 객체인 tistory는 User 인터페이스에서 정의한 모든 property를 구현해야한다.

✅ Abstract class

  • 다른 클래스가 가져야 할 property랑 메소드를 명시할 수 있도록 도와준다.
  • 상속받은 클래스가 어떻게 동작해야할지 일러주기 위해서 추상클래스를 사용한다.

   ⇒ [       추상클래스의 문제점      ] 자바스크립트에서는 abstract의 개념이 없어서 결국 일반 클래스로 바뀐다.

   ⇒ [ 아니 그럴꺼면 왜 사용하지? ] 다른 클래스들이 표준화된 모양 표준화된 property와 메소드를 갖도록 해주는 청사진 
                                                         을 만들기 위해 추상 클래스를 사용한다.


✅ Abstract class vs interface

  • 인터페이스는 추상클래스와 비슷한 보호를 제공하지만, 자바스크립트 파일에서 아예 보이지 않는다.
    (추상클래스는 일반클래스로 변환 → 파일크기가 커지고, 추가 클래스가 만들어진다.)

   ⇒ 추상클래스를 다른 클래스들이 특정 모양을 따르도록 하기 위한 용도로 쓴다면
       같은 역할을 하는 interface를 쓰는게 좋다.

// Abstract class
abstract class User1 {
    constructor(
        protected firstName:string,
        protected lastName:string
    ) {}
    abstract sayHi(name:string):string
    abstract fullName():string
}

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

// Interface
interface User2 {
    firstName:string,
    lastName:string
    sayHi(name:string):string
    fullName():string
}

interface Human {
    health:number
}

class Player2 implements User2, Human{
    constructor(
        public firstName:string,
        public lastName:string,
        public health:number
    ) {}
    fullName() {
        return `${this.firstName} ${this.lastName}`
    }
    sayHi(name:string) {
        return `Hello ${name}. My name is ${this.fullName()}`
    }
}

function makeUser(user:User2) {
    return "hi"
}

makeUser({
    firstName:"오늘도",
    lastName:"코딩하나",
    fullName: () => "xx",
    sayHi: (name) => "string"
})
  • [ interface를 상속하는 것의 문제점 ] private, protected 사용 불가, 무조건 public이여야 한다.
  • interface를 type으로 사용 가능
    argument에 interface를 씀으로써 오브젝트의 모양을 지정할 수 있다.

✅ type vs interface

  • type과 interface 모두 추상 클래스를 대체해서 사용할 수 있다.
  • type과 interface 모두 Typescript에게 오브젝트의 모양을 알려주기 위해서 사용한다.

  • type은 interface에 비해 좀 더 활용할 수 있는게 많다.
    ( type alias, 특정 값들로만 제한 )

  ⇒ Typescript에게 오브젝트의 모양을 알려주기 위해서는 interface를 쓰고,
      나머지 상황에서는 type을 사용하자!

type PlayerA = {
    name: string
}

// type 상속
type PlayerAA = PlayerA & {
    lastName:string
}

const playerA : PlayerAA = {
    name:"tistory",
    lastName:"xxx"
}


interface PlayerB {
    name:string
}

// 나중에 property를 type에 추가하고 싶으면? (type에서는 안돼)
interface PlayerB {
    health:number
}

// interface 상속
interface PlayerBB extends PlayerB {
    lastName:string
}

const playerB : PlayerBB = {
    name:"tistory",
    lastName: "xxx",
    health:10
}

  1️⃣ type과 interface는 상속하는 방법이 다르다.

  • type& 연산자를 사용하여 다른 타입과 교차하여 상속을 구현한다.
    ( 두 타입을 결합하는 방식)

  • interfaceextends 키워드를 사용하여 다른 인터페이스를 상속할 수 있다.
  • 여러 인터페이스에 대한 다중 상속이 가능하다.

  2️⃣ 나중에 property를 추가하고 싶으면?

  • 같은 interface 이름으로 property를 추가해주면 Typescript가 알아서 하나로 합쳐준다.
  • type에서는 불가능하다.

🙋‍♀️ 다형성, 제네릭, 클래스, 인터페이스 종합적으로 사용해보기!

  • 다형성 : 다른 모양의 코드를 가질 수 있게 해준다.
    → 다형성을 이룰 수 있는 방법은 제네릭을 사용하는 것

  • 제네릭 : placeholder 타입을 쓸 수 있게 해준다. (no concrete 타입)
    → Typescript가 placeholder 타입을 concrete 타입으로 변환해준다.
    → 같은 코드를 다른 타입에 대해서 쓸 수 있도록 한다.

   [ 브라우저에서 쓰는 로컬 스토리지 API와 비슷한 API 만들기 ]

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.get("ket")
stringsStorage.set("hello", "how are you")

const booleansStorage = new LocalStorage<boolean>();
booleansStorage.get("xxx")
booleansStorage.set("hello", true)