Published on

How to Set Up a Node.js Project with TypeScript 2022

Authors

How to Set Up a Node.js Project with TypeScript 2022

วิธีการตั้งค่า Node.js โปรเจคให้สามารถรัน TypeScript ได้ พร้อมกับวิธีการนำไปใช้กับ Express อัพเดทปี 2022

สิ่งที่ต้องมี

  • Node.js version 16
  • npm หรือ yarn
  • VS Code

การตั้งค่าโปรเจคให้สามารถรัน TypeScript ได้

  • เริ่มจากสร้างโปรเจคใหม่ และสร้างไฟล์ package.json
mkdir typescript-node
cd typescript-node
npm init -y
  • ติดตั้ง libraries ใน devDepencies
    • typescript เป็นตัวหลักที่ช่วยแปลงจาก TypeScript ไปเป็น JavaScript
    • ts-node เป็นเหมือน dev server ค่อยช่วยแปลงโค้ดจาก TypeScript ไปเป็น JavaScript ในขั้นตอนพัฒนา
    • @tsconfig/node16 config สำหรับ Node.js Version 16
    • nodemon ตัวช่วยให้รันโค้ดใหม่อัตโนมัติ เมื่อมีการแก้ไขโค้ด ทำงานร่วมกับ ts-node
npm i -D typescript ts-node @tsconfig/node16 nodemon
  • สร้างไฟล์ tsconfig.json โดยใช้คำสั่ง
npx tsc --init

และแก้ไขค่าไฟล์ที่แนะนำของเวอร์ชัน 16 ตามนี้

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Node 16",
  "extends": "@tsconfig/node16/tsconfig.json" /* ใช้ node 16 config */,

  "compilerOptions": {
    "lib": ["es2021"] /* กำหนดว่าตอนเขียนด้วย js version อะไร */,
    "module": "commonjs" /* กำหนดว่าจะใช้ module แบบไหน commonjs หรือ esm*/,
    "target": "es2021" /* กำหนดว่าให้ complie เป็น js version อะไร */,

    "outDir": "./dist" /* ระบุโฟลเดอร์ output (JavaScript) */,
    "rootDir": "./src" /* ระบุโฟลเดอร์ sourcecode (TypeScript) */,

    "strict": true /* เปิดใช้ strict type-checking options*/,
    "esModuleInterop": true /* อนุญาติให้ complie ES module เป็น commonjs*/,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node"
  }
}
  • แก้ไข script ไฟล์ package.json
    • dev สำหรับรันโค้ดในโหมดพัฒนา จะทำการ reload อัตโนมัติเมื่อแก้ไขโค้ด
    • build สำหรับแปลงไฟล์เป็น JavaScript สำหรับการนำไปใช้งานจริง
"scripts": {
  "dev": "nodemon",
  "build": "tsc --project ./"
  "prod": "npm run build && node dist/index.js"
},

  • และสร้างไฟล์ nodemon.json
{
  "watch": ["src"],
  "ext": "ts",
  "ignore": ["src/**/*.spec.ts"],
  "exec": "ts-node ./src/index.ts"
}

ทดสอบโค้ด TypeScript

  • สร้างไฟล์ src/index.ts
const geeting = (name: string) => {
  console.log(`Hello ${name} from TypeScript.`)
}

geeting('Ball')
  • รัน npm run dev
> typescript-node@1.0.0 dev D:\workspaces\playgounds\typescript-node
> nodemon

[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): src\**\*
[nodemon] watching extensions: ts
[nodemon] starting `ts-node ./src/index.ts`
Hello Ball from TypeScript.
[nodemon] clean exit - waiting for changes before restart

  • ทดลองแก้ไขชื่อ ตัว nodemon ก็จะ restart ให้อัตโนมัติ
[nodemon] restarting due to changes...
[nodemon] starting `ts-node ./src/index.ts`
Hello Stamp from TypeScript.
[nodemon] clean exit - waiting for changes before restart

  • ทดสอบ build โดยรันคำสั่ง npm run build ก็ได้จะได้โฟลเดอร์ dist ออกมา และมีไฟล์ index.js อยู่ข้างใน
// dist/index.js
'use strict'
const geeting = (name) => {
  console.log(`Hello ${name} from TypeScript.`)
}
geeting('Stamp')

วิธีตั้งค่า TypeScript กับ Express

  • ติดตั้ง Express รัน npm i express
  • สร้าง Express Server ง่ายๆ ที่ไฟล์ src/index.ts
import express from 'express'

const app = express()

const PORT = 8000

app.get('/', (req, res) => res.send('Express + TypeScript Server'))

app.listen(PORT, () => {
  console.log(`Server is running at http://localhost:${PORT}`)
})
  • ทดสอบรัน npm run dev จะพบว่าไม่สามารถรันได้ เนื่องจาก มันไม่รู้จัก type นั่นเอง
  • แก้ไขโดยการติดตั้ง @types ที่ต้องการเพิ่มเข้าไป
npm i -D @types/node @types/express

ถ้าใช้ bodyParser ก็ต้องติดตั้ง @types/body-parser เพิ่มด้วย

  • เมื่อรองรันใหม่อีกครั้งก็จะสามารถรันได้แล้ว
npm run dev

> typescript-node@1.0.0 dev D:\workspaces\playgounds\typescript-node
> nodemon

[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): src\**\*
[nodemon] watching extensions: ts
[nodemon] starting `ts-node ./src/index.ts`
Server is running at http://localhost:8000

ยังไม่หมด

เนื่องจากเราเขียนแบบ TypeScript แต่โค้ดข้างต้นยังไม่ได้ถูกกำหนด type ให้ถูกต้องเลย ดังนั้นเรามากำหนด type ให้ถูกต้องการ ดังนี้

  • app ต้องมี type เป็น Application
  • req ต้องมี type เป็น Request
  • res ต้องมี type เป็น Response
import express, { Application, Request, Response } from 'express'

const app: Application = express()

const PORT: number = 8000

app.get('/', (req: Request, res: Response) => {
  res.send('Express + TypeScript Server')
})

app.listen(PORT, () => {
  console.log(`Server is running at http://localhost:${PORT}`)
})

เท่านี้ก็เรียบร้อยแล้ว

Bonus Linting TypeScript with ESLint

เพิ่มการทำ linting ด้วย ESLint

  • เริ่มจากติดตั้ง eslint และ plugin ที่จำเป็นต้องใช้
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
  • สร้างไฟล์ .eslintrc.js และตั้งค่าตามนี้
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest', // Allows the use of modern ECMAScript features
    sourceType: 'module', // Allows for the use of imports
  },
  plugins: ['@typescript-eslint'],
  env: {
    node: true, // Enable Node.js global variables
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/eslint-recommended',
    'plugin:@typescript-eslint/recommended', // Uses the linting rules from @typescript-eslint/eslint-plugin
  ],
  rules: {
    // https://eslint.org/docs/latest/rules/
    'no-console': 1, // Means warning
  },
}
  • เพิ่มไฟล์ .eslintignore โดยเราจะไม่สนใจ node_modules และ dist
node_modules
dist
  • แก้ไขไฟล์ package.json ให้รัน linting script
"scripts": {
  "dev": "nodemon",
  "build": "tsc --project ./"
  "prod": "npm run build && node dist/index.js"
+ "lint": "eslint . --fix"
},

ใช้งาน Prettier ร่วมกับ ESLint

  • ติดตั้ง plugin และ Prettier rules
npm install --save-dev eslint-config-prettier eslint-plugin-prettier
  • เพิ่มใน .eslintrc.js ตามนี้
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest', // Allows the use of modern ECMAScript features
    sourceType: 'module', // Allows for the use of imports
  },
  plugins: [
		'@typescript-eslint',
+   'prettier'
  ],
  env: {
    node: true, // Enable Node.js global variables
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/eslint-recommended',
    'plugin:@typescript-eslint/recommended', // Uses the linting rules from @typescript-eslint/eslint-plugin
+   'plugin:prettier/recommended',
  ],
  rules: {
    'no-console': 1, // Means warning
+   'prettier/prettier': [
+     'error',
+     {
+       singleQuote: true,
+       parser: 'flow',
+     },
    ],
  },
};
  • กำหนด Prettier Rules โดยสร้างไฟล์ .prettierrc
{
  "useTabs": false,
  "tabWidth": 2,
  "singleQuote": true,
  "printWidth": 120,
  "trailingComma": "es5"
}

จัด format และ lint ทุกครั้งที่ save

เพิ่มการตั้งค่าให้จัด format และ lint ทุกครั้งที่ save โดยเพิ่มไฟล์ .vscode/setting.json ตามนี้

{
  "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnPaste": true,
  "editor.formatOnSave": true,
  "editor.codeActionsOnPaste": {
    "source.fixAll.eslint": true
  },
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

อย่าลืมติดตั้ง Extensions ด้วยนะ