개발 기록 남기기✍️

타입스크립트로 블록체인 만들기 (3) 본문

Front-End/TypeScript

타입스크립트로 블록체인 만들기 (3)

너해동물원 2022. 12. 5. 13:42

[강의로 이동](https://nomadcoders.co/typescript-for-beginners)


Classes

abstract class User {
	constructor (
		private firstName : string,
		private lastName : string,
		protected nickname : string
	){}
	abstract getNickName() : void
	getFullName(){
		return `${this.firstName} ${this.lastName}`
	}
}

class Player extends User {
	getNickName(){
		console.log(this.nickname);
	}
}
const sun = new Player("sun", "yoo", "너해동물원");

sun.firstName // private 이기 때문에 동작하지 않음
sun.nickname // public이여서 외부에서 사용 가능
sun.getFullName();

// in javascript
class Player {
	constructor(firstName, lastName){
		this.firstName = firstName;
		this.lastName = lastName;
	}
		getFullName(){
		return `${this.firstName} ${this.lastName}`
	}
}

class Player extends User {
	constructor (
	) {}
}
const sun = new Player("sun", "yoo", "너해동물원");
sun.nickname;
sun.getFullName();

Javascript에서는 매개변수에 firstName을 받고 constructor 안에 this.firstName = firstName으로 입력해야 하지만, Typescript에서는 constructor 안에 private firstName : string을 적음으로 편하게 선언할 수 있다.

private, public, protected 키워드는 오로지 Typescript에서 개발자를 보호해주기 위해서만 사용하고, Javascript로 전달되진 않는다.

변수에 키워드를 따로 작성하지 않으면, 기본적으로 public 변수가 된다.

 

Abstract Class(추상 클래스)

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

추상 메서드는 추상 클래스를 상속받는 클래스들이 반드시 구현해야하는 메서드이다.

abstract class User {
    constructor (
    protected firstName : string,
    protected lastName : string
    ){}
    abstract sayHi(name : string) : string
    abstract fullName():string
}
new User // 사용 불가능
class Player extends User {
    fullName(){
        return `${this.firstName} ${this.lastName}`
    }
    sayHi(name : string){
        return `Hello ${name}. My name is ${this.fullName}`
    }
}

 

✔️ 접근 가능한 위치

구분 선언한 클래스 내 상속받은 클래스 내
(자식 클래스)
인스턴스
protected
public
private

 

예제) 나만의 사전 만들기

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

class Dict {
	private words : Words
    constructor(){
    	this.words = {}
    } // property 수동으로 초기화 
    add(word : Word){
    	if(this.words[word.term] === undefined){
    		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 Dict();

dict.add(kimchi);
dict.def("kimchi"); // "한국의 음식"

 

심화) 단어를 삭제하는 메소드, 단어를 출력하는 메소드 만들기

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

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

class Dict {
  private words: Words;
  constructor() {
    this.words = {};
  }
  // 단어 추가
  add(word: Word) {
    if (this.words[word.term] === undefined) {
      this.words[word.term] = word.def;
    }
  }
  // 단어 정의 보기
  def(term: string) {
    if (this.words[term]) {
      return this.words[term];
    } else console.log("존재하지 않는 단어입니다.");
  }
  // 단어 삭제
  del(term: string) {
    if (this.words[term]) {
      delete this.words[term];
    } else console.log("정의되지 않은 단어의 삭제 요청입니다.");
  }
  // 단어 정의 수정
  update(word: Word, def: string) {
    if (this.words[word.term] !== def) {
      this.words[word.term] = def;
    } else console.log("정의되지 않은 단어의 수정 요청입니다.");
  }
  // 단어 출력
  list(){
  	console.log(dict.words)
  }
}

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

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

 

Interfaces

  • string 중에서도 특정 string만 입력시키고 싶을 때➡️ type nickname = string | number
  • ➡️type Team = "red" | "blue" | "yellow"
type Team = "red" | "blue" | "yellow"
type Health = 1 | 5 | 10

type Person = {
    name : string,
	age : number,
	job : string 
} // type과 interface 모양 비교!

interface hello = string; // 사용 불가 
interface Player {
	nickname : string,
	team : Team,
	health : Health
}

const sun : Player = {
	nickname : sun,
	team : "red", // 세 가지 옵션 중에서만 선택 가능
	health : 1 // 세 가지 옵션 중에서만 선택 가능
}

 

✔️ interface : 오로지 object의 모양을 Typescript에게 설명해주기 위해서만 사용된다. 객체 지향 프로그래밍의 개념을 활용해서 디자인되었다.

✔️ interfaceproperty들을 축적시킬 수 있다. 똑같은 interface를 여러번 만들면 Typescript가 알아서 하나로 합쳐준다. (`type`에서는 불가능)

✔️ 비교할 점 : type 키워드는 interface 키워드에 비해 좀 더 활용할 수 있는 게 많다. 속성 하나하나에 타입 지정 가능, 타입 앨리어스 가능

 

interface User {
	name : string
}
interface User {
	lastName : string
}
interface User {
	health : number
}


const sun : Player = {
	name : "sun",
    lastName : "yoo",
    health : 10
}

 

interface는 다른 interface에 상속도 가능하다.

Typescript에서 | OR를, &AND를 의미한다.

추상 클래스를 만들면 Javascript에서는 일반 클래스로 변환된다. 추상 클래스는 표준화된 property와 메소드를 갖도록 해주는 청사진을 만들기 위해 사용한다.

➡️ 추상 클래스 대신 interface를 활용하면, interface는 컴파일 과정에서 Javascript로 바뀌지 않고 사라진다. 더 가벼운 코드를 만들 수 있다.

  • 추상 클래스 대신 interface 사용하기
// abstract class
abstract class User {
    constructor (
    protected firstName : string,
    protected lastName : string
    ){}
    abstract sayHi(name : string) : string
    abstract fullName():string
}
new User // 사용 불가능
class Player extends User {
    fullName(){
        return `${this.firstName} ${this.lastName}`
    }
    sayHi(name : string){
        return `Hello ${name}. My name is ${this.fullName}`
    }
}
// interface
interface User {
    firstName : string,
    lastName : string
    sayHi(name : string) : string
    fullName():string
}

interface Human {
    health : number
}

class Player implements User, 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}`
    }
}

 

implements

implements를 사용하여 클래스가 특정 interface를 충족하는지 확인할 수 있다. 클래스를 올바르게 구현하지 못하면 오류가 발생한다.

implements 절은 클래스가 interface 유형으로 처리될 수 있는지를 확인하는 것이다. 클래스의 유형이나 메서드는 전혀 변경되지 않는다.

또한 클래스는 여러 interface를 구현할 수도 있다. class C implements A, B { }

 

Polymorphism with Class, Type, Interface

예제) local Storage 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") // string을 보내주고 string 타입을 받음

const booleansStorage = new LocalStorage<boolean>();

booleansStorage.get("xx"); // string을 보내주고 boolean 타입을 받음