文章目錄
  • 一、搭建 TypeScript + Node.js 項目
  • (一)初始化項目並安裝相關依賴
  • 1、創建項目目錄並初始化
  • 2、安裝必要的依賴包
  • (二)配置 TypeScript 編譯選項(如模塊解析方式適合後端)
  • 二、編寫服務器代碼
  • (一)定義路由類型(使用 Express 等框架)
  • (二)處理請求和響應的類型(包括中間件的類型)
  • 1、請求類型處理
  • 2、響應類型處理
  • 3、中間件類型處理
  • 三、數據庫交互
  • (一)使用 Type - Safe 的數據庫驅動(如 TypeORM)
  • 1、安裝 TypeORM 及相關依賴
  • 2、配置數據庫連接
  • (二)定義數據庫模型和操作的類型(增刪改查)
  • 1、定義數據庫模型(實體類)
  • 2、數據庫操作的類型安全實現(增刪改查)

使用Typescript 開發 Nodejs 命令行工具_User

一、搭建 TypeScript + Node.js 項目

(一)初始化項目並安裝相關依賴

1、創建項目目錄並初始化

首先,創建一個新的項目文件夾,例如通過命令行操作:

mkdir my-node-ts-project
cd my-node-ts-project
npm init -y

npm init -y 命令會初始化一個 package.json 文件,用於管理項目的依賴和相關配置信息,-y 參數表示使用默認配置進行初始化。

2、安裝必要的依賴包

對於一個基於 TypeScript 和 Node.js 的後端項目,需要安裝以下核心依賴:

  • typescript:TypeScript 編譯器,用於將 TypeScript 代碼編譯為 JavaScript 代碼。可以通過以下命令安裝:
    npm install typescript --save-dev

這裏使用 --save-dev 表示將其作為開發依賴安裝,因為它主要在開發階段使用,項目運行時並不直接依賴它。

  • @types/node:這個包提供了 Node.js 相關的類型定義,使得在 TypeScript 代碼中使用 Node.js 的內置模塊(如 http、fs 等)時能夠有類型檢查和智能提示等功能,安裝命令如下:
    npm install @types/node --save-dev

另外,如果計劃使用一些特定的後端框架(如 Express),還需要安裝對應的依賴包以及相應的類型定義包(如 @types/express)。例如安裝 Express:

npm install express
npm install @types/express --save-dev

(二)配置 TypeScript 編譯選項(如模塊解析方式適合後端)

在項目根目錄下創建 tsconfig.json 文件,用於配置 TypeScript 的編譯選項。以下是一個適合後端開發的基本配置示例:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "outDir": "dist",
    "rootDir": "src",
    "strict": true,
    "esModuleInterop": true,
    "sourceMap": true,
    "resolveJsonModule": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules"]
}

解釋一下關鍵配置項:

  • target:指定將 TypeScript 代碼編譯成的 JavaScript 版本,這裏選擇 es6,可以利用一些較新的 JavaScript 特性,同時在大多數 Node.js 環境中也能很好地支持。
  • module:設置模塊系統,commonjs 是 Node.js 常用的模塊規範,便於在後端環境中進行模塊的導入和導出操作。
  • outDir:定義編譯後 JavaScript 文件的輸出目錄,這裏設置為 dist,意味着編譯後的 .js 文件會存放在 dist 文件夾下。
  • rootDir:指定 TypeScript 源代碼的根目錄,通常是 src 文件夾,編譯器會從這個目錄及其子目錄中查找 .ts 文件進行編譯。
  • strict:開啓嚴格模式,啓用全面的類型檢查等功能,有助於提高代碼質量,減少潛在錯誤。
  • esModuleInterop:解決在 CommonJS 和 ES 模塊之間互操作時可能出現的一些問題,方便在項目中同時使用不同模塊規範引入的依賴。
  • sourceMap:生成源映射文件(.map 文件),在調試時能夠將編譯後的 JavaScript 代碼映射回原始的 TypeScript 代碼,方便查找問題。
  • resolveJsonModule:允許在 TypeScript 中直接導入 .json 文件,並將其解析為相應的 JavaScript 對象,這在後端項目中處理配置文件等情況時很有用。

二、編寫服務器代碼

(一)定義路由類型(使用 Express 等框架)

以 Express 框架為例,在 TypeScript 中定義路由時,可以先創建一個路由模塊,然後明確路由處理函數的類型。
例如,創建一個簡單的 userRoutes.ts 文件用於定義用户相關的路由:

import express from 'express';
import { Request, Response } from 'express';

const router = express.Router();

// 定義一個獲取用户信息的路由
router.get('/users/:id', (req: Request, res: Response) => {
  const userId = req.params.id;
  // 這裏可以假設從數據庫等地方獲取用户信息並返回,暫時模擬返回一個固定信息
  const user = { id: userId, name: 'John Doe' };
  res.json(user);
});

export default router;

在上述代碼中:

  • 首先導入了 express 框架以及 express 中的 Request 和 Response 類型定義,它們分別用於描述 HTTP 請求和響應的相關結構和屬性類型。
  • 然後使用 express.Router() 創建了一個路由實例 router,並定義了一個 GET 類型的路由 /users/:id,其處理函數接收 Request 和 Response 類型的參數,在函數內部可以通過 req.params 獲取路由參數(這裏是用户 ID),並根據業務邏輯返回相應的用户信息(這裏簡單地返回了模擬數據,實際中可能會從數據庫查詢等操作獲取真實數據),最後通過 res.json() 方法將數據以 JSON 格式返回給客户端。

(二)處理請求和響應的類型(包括中間件的類型)

1、請求類型處理

除了基本的路由參數獲取,請求對象(Request)還包含很多其他屬性,比如請求頭(headers)、請求體(body)等,在 TypeScript 中可以對它們進行相應的類型定義和處理。
例如,創建一個接收用户註冊信息的路由,需要處理請求體中的 JSON 數據(假設用户註冊信息包含用户名和密碼):

import express from 'express';
import { Request, Response } from 'express';

interface UserRegistration {
  username: string;
  password: string;
}

const router = express.Router();

router.post('/register', (req: Request<{}, {}, UserRegistration>, res: Response) => {
  const userData: UserRegistration = req.body;
  console.log(`Received registration data: ${JSON.stringify(userData)}`);
  // 這裏可以進行後續的業務邏輯,比如將用户信息存入數據庫等操作
  res.status(201).send('Registration successful');
});

export default router;

在這個示例中,定義了 UserRegistration 接口來描述用户註冊信息的結構(包含用户名和密碼兩個屬性,類型都為 string),在路由處理函數的 Request 類型參數中,通過泛型指定了請求體的類型為 UserRegistration,這樣在函數內部就能安全地從 req.body 獲取並使用用户註冊信息了,編譯器會確保類型的一致性。

2、響應類型處理

對於響應對象(Response),可以根據不同的業務需求設置響應狀態碼、響應頭以及返回不同格式的數據等,同樣要遵循類型規範。
例如,在一個返回文件下載的路由中,需要正確設置響應頭來指示文件類型等信息:

import express from 'express';
import { Request, Response } from 'express';
import path from 'path';
import fs from 'fs';

const router = express.Router();

router.get('/download/:filename', (req: Request, res: Response) => {
  const fileName = req.params.filename;
  const filePath = path.join(__dirname, 'uploads', fileName);
  const fileStream = fs.createReadStream(filePath);
  res.setHeader('Content-Type', 'application/octet-stream');
  res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
  fileStream.pipe(res);
});

export default router;

在這個示例中,設置了響應頭的 Content-Type 和 Content-Disposition 屬性,用於告知客户端這是一個文件流下載,並且指定了文件名等信息,整個過程中 res 的各種方法調用(如 setHeader、pipe 等)都符合 Response 類型的定義和要求,確保了響應操作的正確性。

3、中間件類型處理

Express 框架中的中間件在 TypeScript 中也需要進行類型定義,以確保其在處理請求和傳遞控制流時的類型安全。
例如,創建一個簡單的日誌記錄中間件,用於記錄每個請求的相關信息:

import { Request, Response, NextFunction } from 'express';

const loggerMiddleware = (req: Request, res: Response, next: NextFunction) => {
  console.log(`Received request: ${req.method} ${req.url}`);
  next();
};

export default loggerMiddleware;

在這個中間件函數中,參數按照 Request、Response 和 NextFunction(用於調用下一個中間件或路由處理函數的函數類型)的順序定義,在中間件內部可以訪問和處理請求相關的信息,然後通過調用 next() 函數將控制流傳遞給下一個中間件或路由處理函數,遵循了正確的類型規範。

三、數據庫交互

(一)使用 Type - Safe 的數據庫驅動(如 TypeORM)

TypeORM 是一個非常流行的支持 Type - Safe(類型安全)的 Node.js 數據庫 ORM(對象關係映射)框架,它允許使用面向對象的方式與數據庫進行交互,並且在整個過程中利用 TypeScript 的類型系統確保類型的準確性。

1、安裝 TypeORM 及相關依賴

首先需要安裝 TypeORM 以及對應數據庫的驅動(以 MySQL 為例),同時還要安裝 TypeORM 的類型定義包,命令如下:

npm install typeorm mysql2 @types/mysql2
2、配置數據庫連接

在項目中創建一個 ormconfig.json 文件(也可以使用 JavaScript 或 TypeScript 文件來配置,這裏以 .json 文件為例)用於配置數據庫連接相關信息,示例如下:

{
  "type": "mysql",
  "host": "localhost",
  "port": 3306,
  "username": "root",
  "password": "your_password",
  "database": "your_database_name",
  "synchronize": true,
  "logging": true,
  "entities": ["src/entities/*.ts"],
  "migrations": ["src/migrations/*.ts"],
  "subscribers": ["src/subscribers/*.ts"]
}

解釋關鍵配置項:

  • type:指定數據庫類型,這裏是 mysql。
    host、port、username、password、database:分別對應數據庫的主機地址、端口號、用户名、密碼和數據庫名稱,根據實際情況進行填寫。
  • synchronize:設置為 true 時,TypeORM 會自動根據實體類(後面會介紹)的定義來創建、更新數據庫表結構,但在生產環境中要謹慎使用,建議使用數據庫遷移(migrations)來管理表結構變化。
  • logging:開啓日誌記錄,方便查看數據庫操作的相關情況,比如執行的 SQL 語句等。
  • entities:定義了實體類文件的路徑,實體類用於映射數據庫中的表結構,TypeORM 會根據這些實體類來進行數據庫操作。
  • migrations 和 subscribers:分別用於配置數據庫遷移文件和訂閲者文件的路徑,用於更復雜的數據庫結構變更管理和事件監聽等功能。

(二)定義數據庫模型和操作的類型(增刪改查)

1、定義數據庫模型(實體類)

使用 TypeORM,需要創建實體類來描述數據庫中的表結構以及表與表之間的關係。例如,創建一個簡單的 User 實體類,對應數據庫中的 users 表:

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  username: string;

  @Column()
  password: string;
}

export default User;

在上述代碼中:

  • 使用 @Entity() 裝飾器標記這個類是一個實體類,對應數據庫中的一張表。
  • @PrimaryGeneratedColumn() 裝飾器用於定義主鍵列,這裏表示 id 列是自增的主鍵,類型為 number。
  • @Column() 裝飾器用於定義普通列,如 username 和 password 列,分別對應數據庫表中的相應字段,類型都為 string。
2、數據庫操作的類型安全實現(增刪改查)

基於上述定義的實體類,可以進行各種數據庫操作,並且在操作過程中保持類型安全。
例如,進行簡單的查詢操作,獲取所有用户信息:

import { getConnection } from 'typeorm';
import User from './entities/User';

async function getUsers() {
  const connection = await getConnection();
  const users = await connection.getRepository(User).find();
  return users;
}

// 使用示例
(async () => {
  const allUsers = await getUsers();
  console.log(allUsers);
})();

在這個查詢示例中,首先通過 getConnection() 方法獲取數據庫連接,然後使用 connection.getRepository(User) 獲取 User 實體類對應的數據庫操作倉庫,最後調用 find() 方法來查詢所有用户信息,返回的 users 結果類型是 User[],即一個 User 類型的數組,編譯器能夠清楚知道查詢結果的結構,方便後續進行處理(比如遍歷用户列表、訪問用户的各個屬性等操作)。
對於插入數據(新增用户)操作,示例如下:

import { getConnection } from 'typeorm';
import User from './entities/User';

async function createUser(newUser: User) {
  const connection = await getConnection();
  const userRepository = connection.getRepository(User);
  return await userRepository.save(newUser);
}

// 使用示例
(async () => {
  const newUser: User = {
    username: 'new_user',
    password: 'new_password'
  };
  const createdUser = await createUser(newUser);
  console.log(createdUser);
})();

在插入操作中,定義了 createUser 函數接收一個 User 類型的參數 newUser,然後將其保存到數據庫中,返回的 createdUser 同樣是 User 類型,確保了新增數據的類型一致性,整個數據庫的增刪改查操作在 TypeORM 的幫助下都能很好地遵循 TypeScript 的類型規範,減少因類型不匹配等問題導致的錯誤,提高後端代碼的質量和可維護性。