文章目錄
- 一、搭建 TypeScript + Node.js 項目
- (一)初始化項目並安裝相關依賴
- 1、創建項目目錄並初始化
- 2、安裝必要的依賴包
- (二)配置 TypeScript 編譯選項(如模塊解析方式適合後端)
- 二、編寫服務器代碼
- (一)定義路由類型(使用 Express 等框架)
- (二)處理請求和響應的類型(包括中間件的類型)
- 1、請求類型處理
- 2、響應類型處理
- 3、中間件類型處理
- 三、數據庫交互
- (一)使用 Type - Safe 的數據庫驅動(如 TypeORM)
- 1、安裝 TypeORM 及相關依賴
- 2、配置數據庫連接
- (二)定義數據庫模型和操作的類型(增刪改查)
- 1、定義數據庫模型(實體類)
- 2、數據庫操作的類型安全實現(增刪改查)
一、搭建 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 的類型規範,減少因類型不匹配等問題導致的錯誤,提高後端代碼的質量和可維護性。