TypeScript 프로젝트를 설정하고 블록체인 PoC(개념증명)를 객체지향으로 구현해보자!
* CRA나 Next.js의 타입스크립트 템플릿 등을 사용한다면 직접 설정하는 경우는 많지 않다
Targets
npm init -y
터미널에 위 명령어를 입력해 새로운 package.json 파일을 기본값으로 생성한다
npm install -D typescript
터미널에 위 명령어를 입력해 devDependencies에 typescript를 설치해준다
[package.json]
{
"name": "typechain",
"version": "1.0.0",
"description": "",
"scripts": {
"build": "tsc"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"typescript": "^4.6.4"
}
}
위와 같이 수정, npm run build 명령어 또는 tsc 명령어를 실행해 컴파일 할 수 있다
[tsconfig.json]
{
"include": ["src"],
"compilerOptions": {
"outDir": "build",
"target": "ES6",
"moduleResolution": "node"
}
}
tsconfig.json 파일을 생성, 위와 같이 내용을 넣어준다
- include: 컴파일러가 TS 파일을 확인할 폴더를 지정
- outDir: 컴파일된 JS 파일이 저장될 폴더를 지정
- target: TS 파일을 어떤 버전의 JS로 컴파일할지 지정 (ES6 권장)
- moduleResolution: module 관련 import 에러가 발생하는 경우 추가
[src/index.ts]
class Block {
constructor(private data: string) {}
static hello() {
return "hi";
}
}
src 폴더를 생성해 위와 같이 파일을 작성하고..
npm run build
# or
tsc
터미널에 컴파일 명령어를 입력하면..
[build/index.js]
class Block {
constructor(data) {
this.data = data;
}
static hello() {
return "hi";
}
}
지정한 폴더 및 컴파일된 파일이 생성/업데이트된다!
Lib Configuration
[tsconfig.json]
{
"include": ["src"],
"compilerOptions": {
"outDir": "build",
"target": "ES6",
"moduleResolution": "node",
"lib": ["ES6", "DOM"]
}
}
lib 옵션은 TS 파일이 어떤 API를 사용하고 어떤 런타임 환경에서 실행될지 지정한다
- ES6: Math 등 JS 기본 내장 API 사용을 명시
- DOM: localStorage, document, window 등 브라우저 API 사용을 명시
Declaration Files
위와 같은 현상이 가능한 이유는 기본적인 JS API의 타입에 대한 Declaration File (정의 파일)이 지원되기 때문인데, JS 파일로 구성된 외부 패키지/라이브러리에 대해서는 정의 파일을 직접 작성해줘야 하는 경우가 있을 수 있다!
[tsconfig.json]
{
"include": ["src"],
"compilerOptions": {
"outDir": "build",
"target": "ES6",
"moduleResolution": "node",
"lib": ["ES6", "DOM"],
"strict": true
}
}
우선 타입을 엄격하게 검사하는 strict 옵션을 활성화한다
[src/myPackage.js]
export function init(config) {
return true;
}
export function exit(code) {
return code + 1;
}
JS 파일로 구성된 외부 패키지/라이브러리를 사용한다고 가정하고 파일을 생성해준다
[src/myPackage.d.ts]
interface Config {
url: string;
}
declare module "myPackage" {
function init(config: Config): boolean;
function exit(code: number): number;
}
해당 파일에 대한 모듈 및 Call Signature를 선언하는 정의 파일을 생성해준다
[src/index.ts]
import { init, exit } from "myPackage";
init({
url: "true",
});
exit(1);
TS 파일에서 import 가능, 외부 JS 패키지/라이브러리가 모듈로 인식된다
JSDoc
JS 파일과 TS 파일을 혼용하는 경우, 주석에 JSDoc을 작성해 TS 파일과 함께 사용할 수 있다
* JS 프로젝트를 TS로 마이그레이션하는 과정이나 JS 파일의 원본을 유지해야 하는 경우
[tsconfig.json]
{
"include": ["src"],
"compilerOptions": {
"outDir": "build",
"target": "ES6",
"moduleResolution": "node",
"lib": ["ES6", "DOM"],
"strict": true,
"allowJs": true
}
}
정의 파일을 삭제, JS 파일 사용을 허용하는 allowJS 옵션을 활성화한다
[src/index.ts]
import { init, exit } from "./myPackage";
TS 파일에서 JS 파일을 import할 수 있게 되지만 아직 타입을 체크하진 않는다
[src/myPackage.js]
// @ts-check
/**
* Initializes the project
* @param {object} config
* @param {boolean} config.debug
* @param {string} config.url
* @returns boolean
*/
export function init(config) {
return true;
}
/**
* Exits the program
* @param {number} code
* @returns number
*/
export function exit(code) {
return code + 1;
}
위와 같이 JS 파일에서 주석으로 함수의 매개변수 및 반환값의 타입을 지정할 수 있다
Blocks
npm i -D ts-node
빌드와 관계없이 TS 파일을 바로 실행할 수 있도록 해주는 ts-node를 설치해준다
* 프로덕션이 아닌 개발 환경에서만 대신 실행
npm i nodemon
파일을 모니터링, 저장하면 node.js 서버를 자동 재실행해주는 nodemon을 설치해준다
[package.json]
{
"name": "typechain",
"version": "1.0.0",
"description": "",
"scripts": {
"build": "tsc",
"dev": "nodemon --exec ts-node src/index.ts",
"start": "node build/index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"ts-node": "^10.8.0",
"typescript": "^4.6.4"
},
"dependencies": {
"nodemon": "^2.0.16"
}
}
scripts를 위와 같이 추가, npm run dev를 실행하면 개발 환경에서 빌드 없이 파일을 수정/저장할 때마다 터미널에서 index.ts 파일을 실행해주는 상태를 활성화한다
[tsconfig.json]
{
"include": ["src"],
"compilerOptions": {
"outDir": "build",
"target": "ES6",
"moduleResolution": "node",
"lib": ["ES6"],
"strict": true,
"esModuleInterop": true,
"module": "CommonJS"
}
}
- module: JS 파일간 import 문법을 구현할 때 사용할 문법
- esModuleInterop: CommonJS 모듈을 ES6 모듈로 가져오려고 할 때 발생하는 문제 해결
- 브라우저가 아닌 node.js 서버에서 돌아가기 때문에 lib 옵션에서 DOM을 제거
- allowJS 옵션 제거
[src/index.ts]
import crypto from "crypto";
interface BlockShape {
hash: string;
prevHash: string;
height: number;
data: string;
}
class Block implements BlockShape {
public hash: string;
constructor(
public prevHash: string,
public height: number,
public data: string
) {
this.hash = Block.calculateHash(prevHash, height, data);
}
static calculateHash(prevHash: string, height: number, data: string): string {
return `${prevHash}${height}${data}`;
}
}
블록체인을 생성하기 위한 형태를 Block 클래스로 정의해주자
블록체인 개념 간단 정리🔽
Definitely Typed
JS로 작성된 npm 패키지를 import할 때, 일일이 타입 정의 파일을 작성해줄 수는 없다
DefinitelyTyped🔽
DefinitelyTyped 저장소에는 npm에 존재하는 거의 모든 패키지에 대한 타입 정의 파일이 저장되어 있다
npm i -D @types/(패키지 이름)
터미널을 통해 해당 패키지에 대한 타입 정의 파일을 불러올 수 있다
* 최근에는 npm 패키지에 자체에 d.ts 파일을 포함하는 경향
Chain
[src/index.ts]
import crypto from "crypto";
interface BlockShape {
hash: string;
prevHash: string;
height: number;
data: string;
}
class Block implements BlockShape {
public readonly hash: string;
constructor(
public readonly prevHash: string,
public readonly height: number,
public readonly data: string
) {
this.hash = Block.calculateHash(prevHash, height, data);
}
static calculateHash(prevHash: string, height: number, data: string) {
const toHash = `${prevHash}${height}${data}`;
return crypto.createHash("sha256").update(toHash).digest("hex");
}
}
class Blockchain {
private blocks: Block[];
constructor() {
this.blocks = [];
}
private getPrevHash() {
if (this.blocks.length === 0) return "";
return this.blocks[this.blocks.length - 1].hash;
}
public addBlock(data: string) {
const newBlock = new Block(
this.getPrevHash(),
this.blocks.length + 1,
data
);
this.blocks.push(newBlock);
}
public getBlocks(): readonly Block[] {
return [...this.blocks];
}
}
const blockchain = new Blockchain();
blockchain.addBlock("First one");
blockchain.addBlock("Second one");
blockchain.addBlock("Third one");
blockchain.addBlock("Fourth one");
console.log(blockchain.getBlocks());
crypto 패키지를 활용해 간단한 블록체인 PoC를 구현했다!
본 내용은 노마드코더의 'Typescript로 블록체인 만들기'를 바탕으로 작성되었습니다.
'Languages > TypeScript' 카테고리의 다른 글
[wanted] #2 Interface for TypeScript (0) | 2022.09.08 |
---|---|
[wanted] #1 Document for TypeScript (0) | 2022.09.05 |
[노마드코더] #4 Classes and Interfaces (0) | 2022.05.21 |
[노마드코더] #3 Functions (0) | 2022.05.15 |
[노마드코더] #2 Overview of TypeScript (0) | 2022.05.14 |