สอนใช้ TypeScript ในโปรเจค Node.js + Express
Tags: typescript, javascript, programming, tutorial
Published: 2020-09-27 13:57:04


## Node.js กับ TypeScript

Node.js เป็นหนึ่งในเฟรมเวิร์คยอดนิยมสำหรับเขียนโปรแกรมฝั่ง Backend แต่เพราะมันสร้างมาตั้งแต่ปี 2009 ยุคที่ JavaScript ยังเป็นเวอร์ชัน ES5 อยู่เลย

โดยดีฟอลต์แล้ว Node.js เลยไม่ซัพพอร์ท TypeScript เลย ไม่เหมือนกับ [Deno](https://dev.to/centrilliontech/deno-v1-0-javascript-runtime-node-js-39jc) ที่เพิ่งสร้างขึ้นมาโดยซัพพอร์ท TypeScript เป็นค่า default ตั้งแต่แรก

เพื่อชีวิตที่ดีกว่า มาเซ็ตโปรเจค Node.js + Express ให้ใช้ TypeScript ได้กันเถอะ!

## Step 1: ติดตั้ง TypeScript

สำหรับใครที่มี TypeScript อยู่แล้วข้ามสเต็ปนี้ไปได้เลยนะ 

แต่ถ้าใครยังไม่มี ดูวิธีติดตั้งแบบง่ายๆ ได้ที่บทความ [สอนวิธีเซ็ตโปรเจค TypeScript / มาใส่ไทป์ให้ JavaScript เพื่อลดความผิดพลาดในการเขียนโค้ดกันดีกว่า](https://www.centrilliontech.co.th/blog/2851/typescript-setup-project/)

## Step 2: เริ่มสร้างโปรเจค

ปกติเราจะเขียนโค้ด Express หน้าตาประมาณนี้

```js
const express = require('express')

const app = express()

app.get('/', (req, res) => {
    res.send('Hello World!')
})

app.listen(3000)
```

สมมุติว่าเซฟเป็นไฟล์ชื่อ `app.js` ละกัน วิธีที่จะเปลี่ยนมันเป็น TypeScript อย่างแรกเลยคือเปลี่ยนนามสกุลให้กลายเป็น `app.ts`

## Step 3: @types

ปัญหาเมื่อเรานำโค้ด JavaScript ธรรมดามาเปลี่ยนเป็น TypeScript นั่นคือการที่ไทป์หายไป!

TypeScript Compiler หรือ `tsc` ไม่มีทางรู้ได้เลยว่าโค้ดที่เขียนๆ ขึ้นมาใน JavaScript แต่ละตัวมีไทป์เป็นอะไรบ้าง

ดังนั้นเลยต้องมีการ define ให้ TypeScript รู้จัก ซึ่งการทำแบบนั้นไม่ต้องถึงขั้นเขียนโค้ดใหม่ทั้งหมด แต่แค่เพิ่ม `@types` เข้าไปก็พอแล้ว!

ส่วนการติดตั้งก็ไม่ยาก มี npm ใช้ npm, มี yarn ใช้ yarn

```js
//npm
npm i @types/express --save-dev

//yarn
yarn add @types/express --dev
```

> ข้อสังเกตคือ library ยอดนิยมส่วนใหญ่จะมีการทำ types ไว้ให้อยู่แล้ว โดยชื่อของแพกเกจไทป์ส่วนใหญ่จะชื่อเดียวกับชื่อแพกเกจหลัก แต่เติม `@types/` ไว้ข้างหน้า

จากนั้นเราก็กลับไปแก้โค้ดของเราอีกที

สำหรับ TypeScript นั้นจะต้องกำหนดไทป์ให้ตัวแปรทุกตัว เช่น `Application`, `Request`, `Response` ซึ่ง import มาจาก `express` ได้ตรงๆ เลย

```js
import express, { Application, Request, Response } from 'express'

const app: Application = express()

app.get('/', (req: Request, res: Response) => {
    res.send('Hello World!')
})

app.listen(3000)
```

> เวลาจะใช้งานก็ต้องคอมไพล์ให้ออกมาเป็น `.js` ซะก่อนนะ

## Step 4: Watch File

จากสเต็ปที่แล้ว จะพบว่าระหว่างการ develop จะมีขั้นตอนเยอะมากในการรัน
- ต้องคอมไพล์ TypeScript ด้วยคำสั่ง `tsc` ก่อน
- รัน Node ด้วยคำสั่ง `node`
- แล้วถ้ามีการแก้ไข้โค้ดอะไร ก็ต้อง kill process แล้วเริ่มคอมไพล์ตั้งแต่ TypeScript อีกรอบหนึ่งเลย
- ซึ่งเป็นอะไรที่น่ารำคาญและทำให้ Productivity ต่ำมากๆ 

ดังนั้นในสเต็ปสุดท้ายนี้เรามาดูวิธีการเซ็ตคำสั่ง ให้มัน watch file ให้เรากันดีกว่า 

> การ watch file หมายความว่า ให้ node คอยดูถ้าไฟล์ source code ของโปรแกรมมีการเปลี่ยนแปลง (เช่นมีการ save โค้ดตัวใหม่เข้ามา) ให้เริ่มรันโปรแกรมใหม่ด้วยตัวมันเอง เราจะได้ไม่ต้องมาคอยสั่งทุกครั้ง

ตามปกติถ้าเราเขียน Node.js ธรรมดา เราอาจจะใช้แพ็กเกจ เช่น `nodemon` 

```bash
nodemon app.js
```

แต่ถ้าเราเขียนโค้ดในไฟล์ TypeScript อยู่ เราก็ต้องสั่งให้มัน watch file ด้วยอีกต่อหนึ่ง

```bash
tsc --watch
```

> ซึ่งถ้าใช้วิธีนี้จะต้องเปิด Terminal ไว้ 2 อัน อันนึงรัน nodemon อีกอันรัน tsc นะ

หรือเราอาจจะใช้ `ts-node` แทนก็ได้ (อ่านวิธีใช้ `ts-node` และวิธีเซ็ต structure ของโปรเจคได้ที่ [บทความสอนวิธีเซ็ตโปรเจค TypeScript](https://www.centrilliontech.co.th/blog/2851/typescript-setup-project/))

```bash
nodemon --watch 'src/**/*.ts' --ignore 'src/**/*.spec.ts' --exec 'ts-node' src/app.ts
```

นั่นคือเราสั่งให้ nodemon คอยดูไฟล์ทั้งหมดในโฟลเดอร์ `src` ที่เป็นนามสกุล `.ts` ถ้าไฟล์มีการเปลี่ยนแปลง (มีการแก้ไขหรือมีการเซฟใหม่) ให้รันคำสั่ง `ts-node` ใหม่ทันที

หรือถ้าไม่อยากเขียน command ยาวๆ ก็ไปเขียน config ในไฟล์ `nodemon.json` แทนก็ได้

แบบนี้
```bash
{
  "watch": ["src"],
  "ext": "ts",
  "ignore": ["src/**/*.spec.ts"],
  "exec": "ts-node ./src/app.ts" 
  #or 
  "exec": "npx ts-node ./src/app.ts"
}
```

### ใช้ ts-node-dev

หรือใช้อีกวิธีคือลงแพ็กเกจ `ts-node-dev` 

```bash
# npm
yarn add ts-node-dev --dev

# yarn
npm i ts-node-dev --save-dev
```

แล้วก็รันด้วยคำสั่ง

```bash
ts-node-dev app.ts
```