1.Typescript로 블록체인 만들기

6 minute read

1.0 Introuction and What are we building

  • (1).TypeScript 를 사용하는 첫번째 이유
    자바스크립트는 규칙없이 사용하기 쉽고 우리가 원하는 방향대로 수정이 편하다, 하지만 그렇기 때문에 큰 프로젝트를 하거나 팀으로 일할때, 버그를 최소화 하고 싶을때는 단점이 된다. 그렇기에 규칙이 있는 Typescript를 사용하는것이다.
  • (2).아래의 예시를 통해 어떤 차이가 있는지 알수 있다.

    • 아래 코드는 자바스크립트 문법상 어떠한 문제도 없으므로 자바스크립트 엔진은 아무런 이의 제기없이 위 코드를 실행할 것이다. 이러한 상황이 발생한 이유는 변수나 반환값의 타입을 사전에 지정하지 않는 자바스크립트의 동적 타이핑(Dynamic Typing)에 의한 것이다.
    function sum(a, b) {
      return a + b;
    }
    
    sum("x", "y"); // 'xy'
    
    • TypeScript는 정적 타입을 지원하므로 컴파일 단계에서 오류를 포착할 수 있는 장점이 있다. 명시적인 정적 타입 지정은 개발자의 의도를 명확하게 코드로 기술할 수 있다. 이는 코드의 가독성을 높이고 예측할 수 있게 하며 디버깅을 쉽게 한다.
    function sum(a: number, b: number) {
      return a + b;
    }
    
    sum("x", "y");
    // error TS2345: Argument of type '"x"' is not assignable to parameter of type 'number'.
    

1.1 Setting Typescript Up

  • (1).yarn init

  • (2).Typescript 설치

    • npm install typescript –save-dev

  • (3).tsconfig.json 파일 생성

// module : node.js를 평범하게 사용하고 다양한걸 import 하거나 export   있게 만듬
// target : 어떤 버전의 javascript로 컴파일 되고 싶은 지를 적음
// sourceMap : sourcemap 처리여부(true/false)
// include : ["어떤 파일이 컴파일 과정에 포함되는지 Typescript한테 알려줌"]

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "ES2015",
    "sourceMap": true
  },
  "include": ["index.ts"],
  "exclude": ["node_modules"]
}
  • (4).ts 파일 생성 , index.ts

  • (5).ts 를 .js로 바꿈

    • npx tsc

      why ? Node.js는 Typescript를 이해하지 못하기 때문에 Javascript 코드로 컴파일 하는 작업이 필요함

  • (6)yarn start로 index.js를 실행시켜주기 위해 설정(매번 npx tsc를 할 필요없게 하기 위해)

{
  "name": "TypeChain",
  "version": "1.0.0",
  "main": "index.js",
  "repository": "https://github.com/JungYOsup/TypeChain.git",
  "author": "yosup <yosup1004@gmail.com>",
  "license": "MIT",
  "devDependencies": {
    "typescript": "^4.1.3"
  },
  "scripts": {
    "start": "node index.js",
    "prestart": "npx tsc"
    // yarn start  할경우 prestart가 먼저 동작 npx tsc  .ts를 js로 바꿔줌(Node.js는 Typescript를 이해하지 못하기 때문에 Javascript 코드로 컴파일 하는 작업이 필요함)
    //  바꿔준 파일인 index.js  실행시킴
  }
}

1.2 First steps with Typescript

  • (1).TypeScript 를 사용하는 두번째 이유

    • javascript 는 sayHi()의 파라미터에 gender가 선언이 안돼도 undefined가 전달되므로 오류가 안생김
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const name = "jung",
      age = 24,
      gender = "male";
    const sayHi = (name, age, gender) => {
      console.log(`Hello ${name}, you are ${age}, you are a ${gender}`);
    };
    sayHi(name, age);
    //# sourceMappingURL=index.js.map
    
    // 결과값 : Hello jung, you are 24, you are a undefined
    // 장점 : 코드 작성하기가 편하다
    // 단점 : 명시적으로 gender의 파라미터로 값이 들어가는지 안들어가는지 알기가 어렵다.
    
    • typescript는 sayHi()의 파라미터의 geden가 선언이 안돼면 오류가 발생, 명시적으로 파라미터 3개를 넣으라고 알려줌
    const name = "jung",
      age = 24,
      gender = "male";
    
    const sayHi = (name, age, gender) => {
      console.log(`Hello ${name}, you are ${age}, you are a ${gender}`);
    };
    
    sayHi(name, age, gender);
    
    export {};
    
    // index.ts:9:1 - error TS2554: Expected 3 arguments, but got 2.9 sayHi(name, age); index.ts:5:275 const sayHi = (name, age, gender) => {An argument for 'gender' was not provided.Found 1 error.
    
    • 만약 내가 파라미터를 2개를 넣어주고 싶고 gender은 있어도 되고 없어도 될경우에는 어떻게 할까 ? gender 파라미터는 선택적이야
    const name = "jung",
      age = 24,
      gender = "male";
    
    const sayHi = (name, age, gender?) => {
      console.log(`Hello ${name}, you are ${age}, you are a ${gender}`);
    };
    
    sayHi(name, age);
    
    export {};
    // 결과값 : Hello jung, you are 24, you are a undefined
    
    • 또 이렇게 될경우 명시적으로 name, age는 필수로 들어가야하는데 gender은 선택적이구나 라고 코드만 보고 명시적으로 바로 알수가 있다.

1.3 Types in Typescript

  • (1).Typescript는 또 이렇게 명시적으로 type을 정해줄수 있다. 파라미터 옆에 : string 이 의미하는것은 return 타입이 무엇인지를 명시해준다.
const name = "jung";
const age = 24,
  gender = "male";

const sayHi = (name: string, age: number, gender: string): string => {
  return `Hello ${name}, you are ${age}, you are a ${gender}`;
};

sayHi("jung", 24, "안녕");

export {};
  • (2).TSC watch

TSC watch : 원래는 ts코드가 바뀔 때마다 js로 컴파일 한 뒤, node로 실행하는 과정을 반복해야했지만, tsc-watch를 사용하면 ts코드가 바뀔때마다 자동으로 컴파일 해준 뒤 js로 실행시켜준다.

  • (3).TSC watch 설치 순서

    • 1.tsc-watch 설치 : yarn add tsc-watch –dev

    • 2.tsconfig.json 파일 내용 수정

    // module : node.js를 평범하게 사용하고 다양한걸 import 하거나 export   있게 만듬
    // target : 어떤 버전의 javascript로 컴파일 되고 싶은 지를 적는거임
    // sourceMap : sourcemap 처리여부(true/false)
    // include : ["어떤 파일이 컴파일 과정에 포함되는지 Typescript한테 알려줌" , ["src/**/*"] : src안의 모든 ts 파일을 의미함]
    // outDir : compile할 위치를 지정함
    {
      "compilerOptions": {
        "module": "commonjs",
        "target": "ES2015",
        "sourceMap": true,
        "outDir": "dist"
      },
      "include": ["src/**/*"],
      "exclude": ["node_modules"]
    }
    
  • 3.package.json 파일 수정

    {
      "name": "TypeChain",
      "version": "1.0.0",
      "main": "index.js",
      "repository": "https://github.com/JungYOsup/TypeChain.git",
      "author": "yosup <yosup1004@gmail.com>",
      "license": "MIT",
      "devDependencies": {
        "typescript": "^4.1.3"
      },
      "scripts": {
        "start": "tsc-watch --onSuccess \" node dist/index.js \" ",
        // tsc-watch의 실행이 성공하면(--onSuccess) dist 안에 있는 index.js를 실행함
        "prestart": "npx tsc"
      },
      "dependencies": {
        "tsc-watch": "^4.2.9"
      }
    }
    
    • 4.ts값 수정시 node script 할 필요없이 자동으로 수정되는것이 보임

1.4 interface on Typesscript

  • (1).Typescript에서 파리미터를 값이 아닌 객체를 전달하는 방법, interface를 활용한다.

interface란 무엇일까?

인터페이스는 일반적으로 타입 체크를 위해 사용되며 변수, 함수, 클래스에 사용할 수 있다. 인터페이스는 여러가지 타입을 갖는 프로퍼티로 이루어진 새로운 타입을 정의하는 것과 유사하다. 인터페이스에 선언된 프로퍼티 또는 메소드의 구현을 강제하여 일관성을 유지할 수 있도록 하는 것이다. ES6는 인터페이스를 지원하지 않지만 TypeScript는 인터페이스를 지원한다.

인터페이스는 프로퍼티와 메소드를 가질 수 있다는 점에서 클래스와 유사하나 직접 인스턴스를 생성할 수 없고 모든 메소드는 추상 메소드이다. 단, 추상 클래스의 추상 메소드와 달리 abstract 키워드를 사용하지 않는다.

interface Human {
  name: string;
  age: number;
  gender: string;
}

const person = {
  name: "yo",
  age: 23,
  gender: "male",
};

const sayHi = (person: Human): string => {
  return `Hello ${person.name}, you are ${person.age}, you are a ${person.gender}`;
};

console.log(sayHi(person));

export {};

1.5 Classes on Typescript part One

  • (1).TypeScript에서 클래스 사용하기
class Human {
  public name: string;
  public age: number;
  public gender: string;
  constructor(name: string, age: number, gender: string) {
    this.name = name;
    this.age = age;
    this.gender = gender;
  }
}

const lynn = new Human("Lynn", 1, "male");

const sayHi = (person: Human): string => {
  return `Hello ${person.name}, you are ${person.age}, you are a ${person.gender}`;
};

console.log(sayHi(lynn));

export {};
  • (2).private 와 public
  • Java에서 배웠던 것과 같음

1.7 Blockchain Creating a Block

class Block {
  public index: number;
  public hash: string;
  public previousHash: string;
  public data: string;
  public timestamp: number;
  constructor(
    index: number,
    hash: string,
    previousHash: string,
    data: string,
    timestamp: number
  ) {
    this.index = index;
    this.hash = hash;
    this.previousHash = previousHash;
    this.data = data;
    this.timestamp = timestamp;
  }
}

const genesisBlock: Block = new Block(0, "2020202020202", "", "Hello", 123456);

const genesisBlock2: Block = new Block(0, "2020202020202", "", "Hello", 123456);

let blockchain: Block[] = [genesisBlock];

blockchain.push("dd"); //(x) why ? blockchain 변수의 타입이 Block 배열이니까 , Block 타입이 들어가야하는데, dd는 String 타입이므로
blockchain.push(genesisBlock2); // (O)

console.log(blockchain);

export {};

1.8 Creacting a Block part Two

import * as CryptoJs from "crypto-js";

class Block {
  public index: number;
  public hash: string;
  public previousHash: string;
  public data: string;
  public timestamp: number;

  static calculateBlockHash = (
    index: number,
    hash: string,
    previousHash: string,
    data: string,
    timestamp: number
  ): string =>
    CryptoJs.SHA256(index + previousHash + timestamp + data).toString();

  constructor(
    index: number,
    hash: string,
    previousHash: string,
    data: string,
    timestamp: number
  ) {
    this.index = index;
    this.hash = hash;
    this.previousHash = previousHash;
    this.data = data;
    this.timestamp = timestamp;
  }
}

const genesisBlock: Block = new Block(0, "2020202020202", "", "Hello", 123456);

let blockchain: Block[] = [genesisBlock];

const getBlockchain = (): Block[] => blockchain;

const getLatestBlock = (): Block => blockchain[blockchain.length - 1];

const getNewTimeStamp = (): Number => Math.round(new Date().getTime() / 1000);

console.log(blockchain);

export {};

Leave a comment