Node.js之TypeScript支持
安装 TypeScript 与 @types/node
全局安装 TypeScript
javascript
npm install -g typescript
项目级别安装
javascript
// 安装 TypeScript 编译器和 Node.js 类型定义
npm install --save-dev typescript @types/node
// 安装 ts-node 用于直接运行 TypeScript 文件
npm install --save-dev ts-node
// 安装其他常用类型定义
npm install --save-dev @types/express @types/lodash
验证安装
javascript
// 查看 TypeScript 版本
tsc --version
// 查看 ts-node 版本
ts-node --version
初始化 TypeScript 配置文件
生成 tsconfig.json
javascript
// 在项目根目录执行
tsc --init
自定义配置文件结构
javascript
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
常用配置说明
编译选项详解
目标与模块配置
javascript
{
"compilerOptions": {
// 编译目标版本
"target": "ES2020", // ES5, ES6, ES2017, ES2018, ES2019, ES2020, ESNext
// 模块系统
"module": "commonjs", // commonjs, amd, system, umd, es6, es2015, es2020, esnext
// 包含的库文件
"lib": ["ES2020", "DOM"], // 根据运行环境选择
// 模块解析策略
"moduleResolution": "node" // node, classic
}
}
输出配置
javascript
{
"compilerOptions": {
// 输出目录
"outDir": "./dist",
// 根目录
"rootDir": "./src",
// 生成声明文件
"declaration": true,
// 生成源码映射
"sourceMap": true,
// 移除注释
"removeComments": false
}
}
类型检查配置
javascript
{
"compilerOptions": {
// 严格模式
"strict": true,
// 不允许隐式 any
"noImplicitAny": true,
// 严格空值检查
"strictNullChecks": true,
// 严格函数类型检查
"strictFunctionTypes": true,
// 未使用变量检查
"noUnusedLocals": true,
// 未使用参数检查
"noUnusedParameters": true
}
}
添加 TypeScript 代码
基础类型示例
javascript
// src/types/index.ts
export interface User {
id: number;
name: string;
email: string;
isActive: boolean;
createdAt: Date;
}
export type UserRole = 'admin' | 'user' | 'guest';
export interface CreateUserDto {
name: string;
email: string;
role?: UserRole;
}
服务层实现
javascript
// src/services/userService.ts
import { User, CreateUserDto, UserRole } from '../types';
export class UserService {
private users: User[] = [];
private nextId = 1;
async createUser(userData: CreateUserDto): Promise<User> {
const user: User = {
id: this.nextId++,
name: userData.name,
email: userData.email,
isActive: true,
createdAt: new Date()
};
this.users.push(user);
return user;
}
async getUserById(id: number): Promise<User | undefined> {
return this.users.find(user => user.id === id);
}
async getAllUsers(): Promise<User[]> {
return [...this.users];
}
}
Express 应用示例
javascript
// src/app.ts
import express, { Request, Response, NextFunction } from 'express';
import { UserService } from './services/userService';
import { CreateUserDto } from './types';
const app = express();
const userService = new UserService();
app.use(express.json());
// 类型安全的路由处理
app.post('/users', async (req: Request<{}, User, CreateUserDto>, res: Response) => {
try {
const user = await userService.createUser(req.body);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: (error as Error).message });
}
});
app.get('/users/:id', async (req: Request<{ id: string }>, res: Response) => {
const id = parseInt(req.params.id, 10);
const user = await userService.getUserById(id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
export default app;
入口文件
javascript
// src/index.ts
import app from './app';
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
编译 TypeScript 代码
编译流程图
graph TD
A[TypeScript 源码] --> B[类型检查]
B --> C{类型检查通过?}
C -->|是| D[编译为 JavaScript]
C -->|否| E[报告类型错误]
D --> F[生成 .js 文件]
D --> G[生成 .d.ts 声明文件]
D --> H[生成 .map 源码映射]
F --> I[输出到 dist 目录]
G --> I
H --> I
编译命令
javascript
// 编译整个项目
tsc
// 编译特定文件
tsc src/index.ts
// 监听模式编译
tsc --watch
// 编译并忽略类型错误
tsc --noEmitOnError false
package.json 脚本配置
javascript
{
"scripts": {
"build": "tsc",
"build:watch": "tsc --watch",
"clean": "rm -rf dist",
"prebuild": "npm run clean"
}
}
编译输出示例
编译前 (src/index.ts):
javascript
import express from 'express';
const app: express.Application = express();
编译后 (dist/index.js):
javascript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const app = express_1.default();
在 Node.js 中运行 TypeScript 编译后的代码
运行流程图
graph TD
A[npm run build] --> B[TypeScript 编译]
B --> C[生成 JavaScript 文件]
C --> D[node dist/index.js]
D --> E[Node.js 执行]
F[开发环境] --> G[ts-node src/index.ts]
G --> H[直接执行 TypeScript]
生产环境运行
javascript
// 1. 编译项目
npm run build
// 2. 运行编译后的 JavaScript
node dist/index.js
// 3. 使用 PM2 管理进程
pm2 start dist/index.js --name "my-app"
package.json 配置
javascript
{
"main": "dist/index.js",
"scripts": {
"start": "node dist/index.js",
"start:prod": "NODE_ENV=production node dist/index.js",
"build": "tsc",
"prebuild": "npm run clean",
"clean": "rm -rf dist"
}
}
使用 ts-node 直接运行 TypeScript 文件使用 npm 脚本自动化
ts-node 配置
javascript
// 安装 ts-node
npm install --save-dev ts-node
// 直接运行 TypeScript 文件
npx ts-node src/index.ts
// 使用特定 tsconfig
npx ts-node --project tsconfig.dev.json src/index.ts
开发环境脚本配置
javascript
{
"scripts": {
"dev": "ts-node src/index.ts",
"dev:watch": "ts-node --watch src/index.ts",
"dev:debug": "ts-node --inspect src/index.ts",
"test": "ts-node --project tsconfig.test.json test/index.ts"
}
}
nodemon 集成
javascript
// 安装 nodemon
npm install --save-dev nodemon
// nodemon.json 配置
{
"watch": ["src"],
"ext": "ts,json",
"ignore": ["src/**/*.test.ts"],
"exec": "ts-node src/index.ts"
}
// package.json 脚本
{
"scripts": {
"dev": "nodemon",
"dev:debug": "nodemon --exec 'ts-node --inspect src/index.ts'"
}
}
完整的自动化流程
graph TD
A[开发阶段] --> B[ts-node + nodemon]
B --> C[自动重载]
C --> D[类型检查]
D --> E[代码执行]
F[构建阶段] --> G[tsc 编译]
G --> H[类型检查]
H --> I[生成 JavaScript]
I --> J[生产部署]
K[测试阶段] --> L[ts-node 运行测试]
L --> M[Jest/Mocha 执行]
环境变量配置
javascript
// .env 文件
NODE_ENV=development
PORT=3000
DATABASE_URL=mongodb://localhost:27017/myapp
// 在 TypeScript 中使用
import dotenv from 'dotenv';
dotenv.config();
const config = {
port: process.env.PORT || 3000,
nodeEnv: process.env.NODE_ENV || 'development',
databaseUrl: process.env.DATABASE_URL
};
完整的 package.json 示例
javascript
{
"name": "nodejs-typescript-app",
"version": "1.0.0",
"description": "Node.js TypeScript 应用示例",
"main": "dist/index.js",
"scripts": {
"dev": "nodemon",
"build": "tsc",
"start": "node dist/index.js",
"start:prod": "NODE_ENV=production node dist/index.js",
"clean": "rm -rf dist",
"prebuild": "npm run clean",
"test": "jest",
"test:watch": "jest --watch",
"lint": "eslint src/**/*.ts",
"lint:fix": "eslint src/**/*.ts --fix"
},
"devDependencies": {
"@types/node": "^18.0.0",
"@types/express": "^4.17.0",
"typescript": "^4.8.0",
"ts-node": "^10.9.0",
"nodemon": "^2.0.0",
"jest": "^29.0.0",
"@types/jest": "^29.0.0",
"eslint": "^8.0.0",
"@typescript-eslint/parser": "^5.0.0",
"@typescript-eslint/eslint-plugin": "^5.0.0"
},
"dependencies": {
"express": "^4.18.0",
"dotenv": "^16.0.0"
}
}