第8章 模块与命名空间:代码世界的"城市规划"
想象你正在建设一座现代化的智慧城市——模块(Modules) 是功能各异的城区,命名空间(Namespaces) 则是区内的街道网络。如果说前面章节教会了你建造房屋,那么这一章将教你如何规划整座城市!让我们一起掌握TypeScript的代码组织艺术,让大型项目保持井然有序。
8.1 ES模块系统——现代JavaScript的"标准交通网" 🚇
ES模块(ES Modules)是JavaScript官方的模块系统,就像城市的地铁网络一样,连接着各个功能区域。TypeScript对其提供了原生支持,让代码组织变得优雅而高效。
🏗️ 基础模块导入导出:构建代码的"交通枢纽"
// 📁 math.ts - 数学工具模块
/**
* 加法运算函数
* @param a 第一个数字
* @param b 第二个数字
* @returns 两数之和
*/
export function add(a: number, b: number): number {
const result = a + b;
console.log(`计算:${a} + ${b} = ${result}`);
return result;
}
/**
* 减法运算函数
* @param a 被减数
* @param b 减数
* @returns 两数之差
*/
export function subtract(a: number, b: number): number {
const result = a - b;
console.log(`计算:${a} - ${b} = ${result}`);
return result;
}
// 导出常量
export const PI = 3.14159;
export const E = 2.71828;
console.log(`数学常量已定义:PI = ${PI}, E = ${E}`);
// "数学常量已定义:PI = 3.14159, E = 2.71828"
// 默认导出(每个模块仅限一个)
export default class Circle {
constructor(public radius: number) {
console.log(`创建圆形,半径:${radius}`);
}
/**
* 计算圆的面积
* @returns 圆的面积
*/
area(): number {
const result = PI * this.radius ** 2;
console.log(`圆面积计算:π × ${this.radius}² = ${result.toFixed(2)}`);
return result;
}
/**
* 计算圆的周长
* @returns 圆的周长
*/
circumference(): number {
const result = 2 * PI * this.radius;
console.log(`圆周长计算:2π × ${this.radius} = ${result.toFixed(2)}`);
return result;
}
}
// 📁 app.ts - 应用主文件
import Circle, { add, subtract, PI, E } from './math';
console.log('=== 模块导入演示 ===');
// "=== 模块导入演示 ==="
// 使用导入的函数
const sum = add(10, 5);
// "计算:10 + 5 = 15"
console.log(`加法结果:${sum}`); // "加法结果:15"
const difference = subtract(10, 3);
// "计算:10 - 3 = 7"
console.log(`减法结果:${difference}`); // "减法结果:7"
// 使用导入的常量
console.log(`圆周率:${PI}`); // "圆周率:3.14159"
console.log(`自然常数:${E}`); // "自然常数:2.71828"
// 使用默认导出的类
const circle = new Circle(5);
// "创建圆形,半径:5"
const area = circle.area();
// "圆面积计算:π × 5² = 78.54"
console.log(`圆面积:${area.toFixed(2)}`); // "圆面积:78.54"
const circumference = circle.circumference();
// "圆周长计算:2π × 5 = 31.42"
console.log(`圆周长:${circumference.toFixed(2)}`); // "圆周长:31.42"
🎯 高级导入技巧:灵活的"交通路线"
// 📁 utils.ts - 工具函数模块
export const formatDate = (date: Date): string => {
const formatted = date.toISOString().split('T')[0];
console.log(`格式化日期:${date} -> ${formatted}`);
return formatted;
};
export const formatCurrency = (amount: number): string => {
const formatted = `$${amount.toFixed(2)}`;
console.log(`格式化货币:${amount} -> ${formatted}`);
return formatted;
};
export const generateId = (): string => {
const id = Math.random().toString(36).substr(2, 9);
console.log(`生成ID:${id}`);
return id;
};
// 📁 advanced-import.ts - 高级导入示例
// 1. 别名导入 - 避免命名冲突
import { PI as MathPI } from './math';
import { formatDate as dateFormatter } from './utils';
console.log('=== 别名导入演示 ===');
// "=== 别名导入演示 ==="
console.log(`数学常量π:${MathPI}`); // "数学常量π:3.14159"
const today = new Date();
const formattedToday = dateFormatter(today);
// "格式化日期:Mon Jan 01 2024 12:00:00 GMT+0800 (CST) -> 2024-01-01"
console.log(`今天的日期:${formattedToday}`); // "今天的日期:2024-01-01"
// 2. 整体导入 - 命名空间式访问
import * as MathUtils from './math';
import * as Utils from './utils';
console.log('=== 整体导入演示 ===');
// "=== 整体导入演示 ==="
const result = MathUtils.add(20, 30);
// "计算:20 + 30 = 50"
console.log(`使用命名空间调用:${result}`); // "使用命名空间调用:50"
const newCircle = new MathUtils.default(10);
// "创建圆形,半径:10"
const price = 99.99;
const formattedPrice = Utils.formatCurrency(price);
// "格式化货币:99.99 -> $99.99"
console.log(`格式化价格:${formattedPrice}`); // "格式化价格:$99.99"
const uniqueId = Utils.generateId();
// "生成ID:abc123def"
console.log(`生成的ID:${uniqueId}`); // "生成的ID:abc123def"
// 3. 动态导入 - 按需加载
async function loadMathModule() {
console.log('开始动态加载数学模块...');
// "开始动态加载数学模块..."
try {
const mathModule = await import('./math');
console.log('数学模块加载成功');
// "数学模块加载成功"
const dynamicResult = mathModule.add(100, 200);
// "计算:100 + 200 = 300"
console.log(`动态导入计算结果:${dynamicResult}`); // "动态导入计算结果:300"
return mathModule;
} catch (error) {
console.error('模块加载失败:', error);
return null;
}
}
// 使用动态导入
loadMathModule().then(module => {
if (module) {
console.log('动态导入演示完成');
// "动态导入演示完成"
}
});
🌟 模块的核心优势
优势特性 | 说明 | 实际效果 |
---|---|---|
明确依赖 | import/export明确声明依赖关系 | 便于代码分析和优化 |
静态分析 | 编译时确定模块结构 | 支持Tree Shaking等优化 |
作用域隔离 | 每个模块有独立作用域 | 避免全局变量污染 |
浏览器支持 | 原生支持<script type="module"> | 无需额外转换工具 |
按需加载 | 支持动态import() | 提升应用性能 |
8.2 命名空间——TypeScript的"老城区规划" 🏛️
命名空间(Namespaces)是TypeScript早期的代码组织方式,就像城市中的传统街区一样,虽然不如现代模块系统先进,但在特定场景下仍有其价值。
🏗️ 基础命名空间:传统的"街区规划"
// 📁 shapes.ts - 图形命名空间
namespace Shapes {
// 导出接口
export interface Point {
x: number;
y: number;
}
export interface Circle {
center: Point;
radius: number;
}
// 导出类
export class Rectangle {
constructor(
public width: number,
public height: number,
public position: Point = { x: 0, y: 0 }
) {
console.log(`创建矩形:宽${width} × 高${height},位置(${position.x}, ${position.y})`);
}
/**
* 计算矩形面积
* @returns 矩形面积
*/
area(): number {
const result = this.width * this.height;
console.log(`矩形面积:${this.width} × ${this.height} = ${result}`);
return result;
}
/**
* 移动矩形位置
* @param newPosition 新位置
*/
moveTo(newPosition: Point): void {
console.log(`移动矩形:从(${this.position.x}, ${this.position.y})到(${newPosition.x}, ${newPosition.y})`);
this.position = newPosition;
}
}
// 导出函数
export function calculateDistance(p1: Point, p2: Point): number {
const distance = Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2);
console.log(`计算距离:(${p1.x}, ${p1.y})到(${p2.x}, ${p2.y}) = ${distance.toFixed(2)}`);
return distance;
}
// 内部函数(不导出)
function validatePoint(point: Point): boolean {
const isValid = typeof point.x === 'number' && typeof point.y === 'number';
console.log(`验证点坐标:(${point.x}, ${point.y}) - ${isValid ? '有效' : '无效'}`);
return isValid;
}
export function createValidPoint(x: number, y: number): Point | null {
const point = { x, y };
return validatePoint(point) ? point : null;
}
}
// 📁 app.ts - 使用命名空间
/// <reference path="shapes.ts" />
console.log('=== 命名空间演示 ===');
// "=== 命名空间演示 ==="
// 创建点对象
const point1: Shapes.Point = { x: 10, y: 20 };
const point2: Shapes.Point = { x: 30, y: 40 };
console.log(`点1坐标:(${point1.x}, ${point1.y})`); // "点1坐标:(10, 20)"
console.log(`点2坐标:(${point2.x}, ${point2.y})`); // "点2坐标:(30, 40)"
// 计算两点距离
const distance = Shapes.calculateDistance(point1, point2);
// "计算距离:(10, 20)到(30, 40) = 28.28"
console.log(`两点距离:${distance.toFixed(2)}`); // "两点距离:28.28"
// 创建矩形
const rect = new Shapes.Rectangle(100, 50, point1);
// "创建矩形:宽100 × 高50,位置(10, 20)"
const rectArea = rect.area();
// "矩形面积:100 × 50 = 5000"
console.log(`矩形面积:${rectArea}`); // "矩形面积:5000"
// 移动矩形
rect.moveTo(point2);
// "移动矩形:从(10, 20)到(30, 40)"
// 创建圆形对象
const circle: Shapes.Circle = {
center: { x: 0, y: 0 },
radius: 25
};
console.log(`圆心:(${circle.center.x}, ${circle.center.y}),半径:${circle.radius}`);
// "圆心:(0, 0),半径:25"
// 验证点坐标
const validPoint = Shapes.createValidPoint(15, 25);
if (validPoint) {
console.log(`创建有效点:(${validPoint.x}, ${validPoint.y})`);
// "验证点坐标:(15, 25) - 有效"
// "创建有效点:(15, 25)"
}
🏢 嵌套命名空间:多层级的"城区规划"
// 📁 app-system.ts - 应用系统命名空间
namespace App {
// 用户管理子命名空间
export namespace User {
export interface UserInfo {
id: string;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
}
export class UserManager {
private users: UserInfo[] = [];
/**
* 添加用户
* @param user 用户信息
*/
addUser(user: UserInfo): void {
this.users.push(user);
console.log(`添加用户:${user.name} (${user.role})`);
console.log(`当前用户总数:${this.users.length}`);
}
/**
* 查找用户
* @param id 用户ID
* @returns 用户信息或undefined
*/
findUser(id: string): UserInfo | undefined {
const user = this.users.find(u => u.id === id);
console.log(`查找用户 ${id}:${user ? '找到' : '未找到'}`);
return user;
}
/**
* 获取所有用户
* @returns 用户列表
*/
getAllUsers(): UserInfo[] {
console.log(`获取所有用户,共${this.users.length}个`);
return [...this.users];
}
}
}
// 工具函数子命名空间
export namespace Utils {
/**
* 记录日志
* @param level 日志级别
* @param message 日志消息
*/
export function log(level: 'info' | 'warn' | 'error', message: string): void {
const timestamp = new Date().toISOString();
const logMessage = `[${timestamp}] ${level.toUpperCase()}: ${message}`;
console.log(logMessage);
}
/**
* 生成唯一ID
* @param prefix 前缀
* @returns 唯一ID
*/
export function generateId(prefix: string = 'id'): string {
const id = `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`;
console.log(`生成ID:${id}`);
return id;
}
/**
* 延迟执行
* @param ms 延迟毫秒数
* @returns Promise
*/
export function delay(ms: number): Promise<void> {
console.log(`开始延迟 ${ms}ms`);
return new Promise(resolve => {
setTimeout(() => {
console.log(`延迟 ${ms}ms 完成`);
resolve();
}, ms);
});
}
}
// 配置子命名空间
export namespace Config {
export const APP_NAME = 'TypeScript Demo App';
export const VERSION = '1.0.0';
export const DEBUG = true;
export interface DatabaseConfig {
host: string;
port: number;
database: string;
}
export const database: DatabaseConfig = {
host: 'localhost',
port: 5432,
database: 'demo_db'
};
/**
* 获取应用信息
* @returns 应用信息字符串
*/
export function getAppInfo(): string {
const info = `${APP_NAME} v${VERSION} (Debug: ${DEBUG})`;
console.log(`应用信息:${info}`);
return info;
}
}
}
// 使用嵌套命名空间
console.log('=== 嵌套命名空间演示 ===');
// "=== 嵌套命名空间演示 ==="
// 获取应用信息
const appInfo = App.Config.getAppInfo();
// "应用信息:TypeScript Demo App v1.0.0 (Debug: true)"
console.log(appInfo); // "TypeScript Demo App v1.0.0 (Debug: true)"
// 创建用户管理器
const userManager = new App.User.UserManager();
// 生成用户ID
const userId1 = App.Utils.generateId('user');
// "生成ID:user_1704067200000_abc12"
const userId2 = App.Utils.generateId('user');
// "生成ID:user_1704067200001_def34"
// 添加用户
const user1: App.User.UserInfo = {
id: userId1,
name: '张三',
email: 'zhangsan@example.com',
role: 'admin'
};
const user2: App.User.UserInfo = {
id: userId2,
name: '李四',
email: 'lisi@example.com',
role: 'user'
};
userManager.addUser(user1);
// "添加用户:张三 (admin)"
// "当前用户总数:1"
userManager.addUser(user2);
// "添加用户:李四 (user)"
// "当前用户总数:2"
// 查找用户
const foundUser = userManager.findUser(userId1);
// "查找用户 user_1704067200000_abc12:找到"
if (foundUser) {
console.log(`找到用户:${foundUser.name}`);
// "找到用户:张三"
}
// 记录日志
App.Utils.log('info', '用户管理系统初始化完成');
// "[2024-01-01T12:00:00.000Z] INFO: 用户管理系统初始化完成"
App.Utils.log('warn', '这是一个警告消息');
// "[2024-01-01T12:00:00.001Z] WARN: 这是一个警告消息"
// 异步延迟示例
App.Utils.delay(1000).then(() => {
App.Utils.log('info', '延迟操作完成');
// "开始延迟 1000ms"
// (1秒后)
// "延迟 1000ms 完成"
// "[2024-01-01T12:00:01.000Z] INFO: 延迟操作完成"
});
⚠️ 命名空间的适用场景
使用场景 | 推荐度 | 原因 |
---|---|---|
新项目 | ❌ 不推荐 | ES模块更现代、标准 |
旧项目迁移 | ✅ 推荐 | 兼容现有代码结构 |
全局脚本环境 | ✅ 推荐 | 避免全局污染 |
类型声明文件 | ✅ 推荐 | 组织复杂类型定义 |
浏览器直接使用 | ⚡ 可选 | 无需构建工具 |
8.3 模块解析策略——寻找模块的"导航规则" 🗺️
模块解析(Module Resolution)是TypeScript编译器定位导入模块的过程,就像城市的GPS导航系统一样,决定了如何找到目标"地址"。
🧭 解析策略对比:两种"导航模式"
策略类型 | 说明 | 适用场景 | 配置方式 |
---|---|---|---|
classic | TypeScript传统方式 | 已弃用,仅兼容 | "moduleResolution": "classic" |
node | 模拟Node.js的require() | 现代项目推荐 | "moduleResolution": "node" |
bundler | 现代打包工具优化 | Webpack/Vite项目 | "moduleResolution": "bundler" |
🔍 Node策略解析过程:详细的"寻址流程"
// 📁 项目结构示例
/*
project/
├── src/
│ ├── app.ts
│ ├── services/
│ │ ├── user.ts
│ │ ├── user.d.ts
│ │ └── api/
│ │ ├── index.ts
│ │ └── client.ts
│ └── utils/
│ ├── helpers.ts
│ └── index.ts
├── node_modules/
│ └── lodash/
│ ├── package.json
│ └── index.js
└── tsconfig.json
*/
// 📁 src/app.ts - 演示模块解析
console.log('=== 模块解析演示 ===');
// "=== 模块解析演示 ==="
// 1. 相对路径导入 - 解析过程演示
import { getUserInfo } from './services/user';
/*
解析顺序:
1. 检查 ./services/user.ts ✓
2. 检查 ./services/user.tsx
3. 检查 ./services/user.d.ts
4. 检查 ./services/user/package.json
5. 检查 ./services/user/index.ts
*/
const user = getUserInfo('123');
console.log('用户信息获取完成');
// "用户信息获取完成"
// 2. 目录导入 - 自动查找index文件
import { formatDate, formatCurrency } from './utils';
/*
解析顺序:
1. 检查 ./utils.ts
2. 检查 ./utils.tsx
3. 检查 ./utils.d.ts
4. 检查 ./utils/package.json (查找"types"字段)
5. 检查 ./utils/index.ts ✓
*/
const today = new Date();
const formattedDate = formatDate(today);
console.log(`格式化日期:${formattedDate}`);
// "格式化日期:2024-01-01"
const price = 99.99;
const formattedPrice = formatCurrency(price);
console.log(`格式化价格:${formattedPrice}`);
// "格式化价格:$99.99"
// 3. 非相对路径导入 - 查找node_modules
import _ from 'lodash';
/*
解析顺序:
1. 检查 node_modules/lodash.ts
2. 检查 node_modules/lodash.tsx
3. 检查 node_modules/lodash.d.ts
4. 检查 node_modules/lodash/package.json (查找"types"或"typings"字段) ✓
5. 检查 node_modules/lodash/index.ts
6. 向上级目录查找 ../node_modules/lodash/...
*/
const numbers = [1, 2, 3, 4, 5];
const doubled = _.map(numbers, n => n * 2);
console.log(`数组映射结果:${doubled}`);
// "数组映射结果:2,4,6,8,10"
// 📁 src/services/user.ts - 用户服务模块
export interface User {
id: string;
name: string;
email: string;
createdAt: Date;
}
/**
* 获取用户信息
* @param userId 用户ID
* @returns 用户信息
*/
export function getUserInfo(userId: string): User {
console.log(`获取用户信息:${userId}`);
// 模拟数据库查询
const user: User = {
id: userId,
name: `用户${userId}`,
email: `user${userId}@example.com`,
createdAt: new Date()
};
console.log(`用户信息:${JSON.stringify(user, null, 2)}`);
return user;
}
/**
* 更新用户信息
* @param userId 用户ID
* @param updates 更新数据
* @returns 更新后的用户信息
*/
export function updateUser(userId: string, updates: Partial<User>): User {
console.log(`更新用户 ${userId}:`, updates);
const currentUser = getUserInfo(userId);
const updatedUser = { ...currentUser, ...updates };
console.log(`用户更新完成:${updatedUser.name}`);
return updatedUser;
}
// 📁 src/utils/index.ts - 工具函数入口
/**
* 格式化日期
* @param date 日期对象
* @returns 格式化的日期字符串
*/
export function formatDate(date: Date): string {
const formatted = date.toISOString().split('T')[0];
console.log(`日期格式化:${date.toDateString()} -> ${formatted}`);
return formatted;
}
/**
* 格式化货币
* @param amount 金额
* @param currency 货币符号
* @returns 格式化的货币字符串
*/
export function formatCurrency(amount: number, currency: string = '$'): string {
const formatted = `${currency}${amount.toFixed(2)}`;
console.log(`货币格式化:${amount} -> ${formatted}`);
return formatted;
}
/**
* 生成随机字符串
* @param length 字符串长度
* @returns 随机字符串
*/
export function randomString(length: number = 8): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
console.log(`生成随机字符串:${result}`);
return result;
}
// 重新导出其他工具
export * from './helpers';
// 📁 src/utils/helpers.ts - 辅助工具函数
/**
* 防抖函数
* @param func 要防抖的函数
* @param delay 延迟时间
* @returns 防抖后的函数
*/
export function debounce<T extends (...args: any[]) => any>(
func: T,
delay: number
): (...args: Parameters<T>) => void {
let timeoutId: NodeJS.Timeout;
return (...args: Parameters<T>) => {
console.log(`防抖函数调用,延迟${delay}ms`);
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
console.log('防抖函数执行');
func.apply(null, args);
}, delay);
};
}
/**
* 节流函数
* @param func 要节流的函数
* @param delay 节流间隔
* @returns 节流后的函数
*/
export function throttle<T extends (...args: any[]) => any>(
func: T,
delay: number
): (...args: Parameters<T>) => void {
let lastCall = 0;
return (...args: Parameters<T>) => {
const now = Date.now();
if (now - lastCall >= delay) {
console.log('节流函数执行');
lastCall = now;
func.apply(null, args);
} else {
console.log(`节流函数跳过,距离上次调用${now - lastCall}ms`);
}
};
}
🛠️ 路径别名配置:自定义"快捷路径"
// 📁 tsconfig.json - TypeScript配置文件
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node",
"baseUrl": "./src",
"paths": {
"@/*": ["*"],
"@services/*": ["services/*"],
"@utils/*": ["utils/*"],
"@components/*": ["components/*"],
"@types/*": ["types/*"]
},
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
// 📁 src/app-with-aliases.ts - 使用路径别名
console.log('=== 路径别名演示 ===');
// "=== 路径别名演示 ==="
// 使用别名导入 - 简洁清晰
import { getUserInfo, updateUser } from '@services/user';
import { formatDate, formatCurrency, debounce } from '@utils';
import type { User } from '@services/user';
// 创建防抖函数
const debouncedLog = debounce((message: string) => {
console.log(`防抖日志:${message}`);
}, 500);
// 模拟用户操作
const userId = 'user_001';
const user = getUserInfo(userId);
// "获取用户信息:user_001"
// "用户信息:{...}"
// 更新用户信息
const updatedUser = updateUser(userId, {
name: '张三',
email: 'zhangsan@example.com'
});
// "更新用户 user_001:" { name: '张三', email: 'zhangsan@example.com' }
// "获取用户信息:user_001"
// "用户信息:{...}"
// "用户更新完成:张三"
// 格式化显示
const displayDate = formatDate(updatedUser.createdAt);
const displayPrice = formatCurrency(199.99);
console.log(`用户创建日期:${displayDate}`);
// "日期格式化:Mon Jan 01 2024 -> 2024-01-01"
// "用户创建日期:2024-01-01"
console.log(`商品价格:${displayPrice}`);
// "货币格式化:199.99 -> $199.99"
// "商品价格:$199.99"
// 测试防抖函数
debouncedLog('第一次调用');
// "防抖函数调用,延迟500ms"
debouncedLog('第二次调用');
// "防抖函数调用,延迟500ms"
debouncedLog('第三次调用');
// "防抖函数调用,延迟500ms"
// (500ms后)
// "防抖函数执行"
// "防抖日志:第三次调用"
🎯 模块解析最佳实践
- 优先使用相对路径:明确的依赖关系
- 配置路径别名:简化长路径导入
- 统一导入风格:保持代码一致性
- 合理组织目录:便于模块查找
- 使用index文件:简化目录导入
8.4 声明合并——TypeScript的"和平统一" 🤝
声明合并(Declaration Merging)是TypeScript的独特功能,允许将多个同名声明合并为单个定义,就像城市规划中的"区域整合"一样。
🔗 接口合并:扩展现有定义
// 📁 user-base.ts - 基础用户接口
interface User {
id: string;
name: string;
}
console.log('=== 接口合并演示 ===');
// "=== 接口合并演示 ==="
// 第一次扩展 - 添加联系信息
interface User {
email: string;
phone?: string;
}
// 第二次扩展 - 添加权限信息
interface User {
role: 'admin' | 'user' | 'guest';
permissions: string[];
lastLogin?: Date;
}
// 合并结果:
// interface User {
// id: string;
// name: string;
// email: string;
// phone?: string;
// role: 'admin' | 'user' | 'guest';
// permissions: string[];
// lastLogin?: Date;
// }
/**
* 创建用户对象
* @param userData 用户数据
* @returns 完整的用户对象
*/
function createUser(userData: Partial<User> & Pick<User, 'id' | 'name' | 'email' | 'role'>): User {
const user: User = {
id: userData.id,
name: userData.name,
email: userData.email,
role: userData.role,
permissions: userData.permissions || [],
phone: userData.phone,
lastLogin: userData.lastLogin
};
console.log(`创建用户:${user.name} (${user.role})`);
console.log(`权限列表:${user.permissions.join(', ') || '无'}`);
return user;
}
// 使用合并后的接口
const adminUser = createUser({
id: 'admin_001',
name: '管理员',
email: 'admin@example.com',
role: 'admin',
permissions: ['read', 'write', 'delete'],
phone: '13800138000',
lastLogin: new Date()
});
// "创建用户:管理员 (admin)"
// "权限列表:read, write, delete"
const regularUser = createUser({
id: 'user_001',
name: '普通用户',
email: 'user@example.com',
role: 'user',
permissions: ['read']
});
// "创建用户:普通用户 (user)"
// "权限列表:read"
console.log(`管理员邮箱:${adminUser.email}`); // "管理员邮箱:admin@example.com"
console.log(`普通用户权限:${regularUser.permissions.length}个`); // "普通用户权限:1个"
🏢 命名空间合并:功能模块整合
// 📁 api-core.ts - API核心功能
namespace API {
export const BASE_URL = 'https://api.example.com';
export const VERSION = 'v1';
/**
* 构建完整的API URL
* @param endpoint 端点路径
* @returns 完整URL
*/
export function buildUrl(endpoint: string): string {
const url = `${BASE_URL}/${VERSION}${endpoint}`;
console.log(`构建API URL:${url}`);
return url;
}
}
// 📁 api-auth.ts - API认证功能
namespace API {
export interface AuthToken {
access_token: string;
refresh_token: string;
expires_in: number;
}
let currentToken: AuthToken | null = null;
/**
* 设置认证令牌
* @param token 认证令牌
*/
export function setAuthToken(token: AuthToken): void {
currentToken = token;
console.log(`设置认证令牌,过期时间:${token.expires_in}秒`);
}
/**
* 获取认证头部
* @returns 认证头部对象
*/
export function getAuthHeaders(): Record<string, string> {
if (!currentToken) {
console.log('警告:未设置认证令牌');
return {};
}
const headers = {
'Authorization': `Bearer ${currentToken.access_token}`,
'Content-Type': 'application/json'
};
console.log('获取认证头部');
return headers;
}
/**
* 检查令牌是否有效
* @returns 是否有效
*/
export function isTokenValid(): boolean {
if (!currentToken) {
console.log('令牌检查:未设置令牌');
return false;
}
// 简化的过期检查
const isValid = currentToken.expires_in > 0;
console.log(`令牌检查:${isValid ? '有效' : '已过期'}`);
return isValid;
}
}
// 📁 api-requests.ts - API请求功能
namespace API {
export interface RequestOptions {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
body?: any;
headers?: Record<string, string>;
}
/**
* 发送API请求
* @param endpoint 端点路径
* @param options 请求选项
* @returns Promise响应
*/
export async function request<T = any>(
endpoint: string,
options: RequestOptions = {}
): Promise<T> {
const url = buildUrl(endpoint); // 使用合并的函数
const authHeaders = getAuthHeaders(); // 使用合并的函数
const requestOptions = {
method: options.method || 'GET',
headers: {
...authHeaders,
...options.headers
},
body: options.body ? JSON.stringify(options.body) : undefined
};
console.log(`发送${requestOptions.method}请求到:${url}`);
console.log(`请求头:`, requestOptions.headers);
// 模拟网络请求
return new Promise((resolve) => {
setTimeout(() => {
const mockResponse = {
success: true,
data: { message: '请求成功', endpoint },
timestamp: new Date().toISOString()
} as T;
console.log(`请求响应:`, mockResponse);
resolve(mockResponse);
}, 1000);
});
}
/**
* GET请求快捷方法
* @param endpoint 端点路径
* @returns Promise响应
*/
export function get<T = any>(endpoint: string): Promise<T> {
return request<T>(endpoint, { method: 'GET' });
}
/**
* POST请求快捷方法
* @param endpoint 端点路径
* @param data 请求数据
* @returns Promise响应
*/
export function post<T = any>(endpoint: string, data: any): Promise<T> {
return request<T>(endpoint, { method: 'POST', body: data });
}
}
// 使用合并后的命名空间
console.log('=== 命名空间合并演示 ===');
// "=== 命名空间合并演示 ==="
// 设置认证令牌
const token: API.AuthToken = {
access_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
refresh_token: 'refresh_token_here',
expires_in: 3600
};
API.setAuthToken(token);
// "设置认证令牌,过期时间:3600秒"
// 检查令牌状态
const isValid = API.isTokenValid();
// "令牌检查:有效"
console.log(`令牌状态:${isValid ? '有效' : '无效'}`); // "令牌状态:有效"
// 发送GET请求
API.get('/users').then(response => {
console.log('GET请求完成');
// "构建API URL:https://api.example.com/v1/users"
// "获取认证头部"
// "发送GET请求到:https://api.example.com/v1/users"
// "请求头:" { Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', Content-Type: 'application/json' }
// (1秒后)
// "请求响应:" { success: true, data: { message: '请求成功', endpoint: '/users' }, timestamp: '2024-01-01T12:00:00.000Z' }
// "GET请求完成"
});
// 发送POST请求
const userData = {
name: '新用户',
email: 'newuser@example.com'
};
API.post('/users', userData).then(response => {
console.log('POST请求完成');
// "构建API URL:https://api.example.com/v1/users"
// "获取认证头部"
// "发送POST请求到:https://api.example.com/v1/users"
// "请求头:" { Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', Content-Type: 'application/json' }
// (1秒后)
// "请求响应:" { success: true, data: { message: '请求成功', endpoint: '/users' }, timestamp: '2024-01-01T12:00:01.000Z' }
// "POST请求完成"
});
🎭 类与命名空间合并:功能增强
// 📁 form-validator.ts - 表单验证器
class FormValidator {
private errors: string[] = [];
constructor(private formData: Record<string, any>) {
console.log('创建表单验证器');
console.log('表单数据:', formData);
}
/**
* 验证表单
* @returns 验证是否通过
*/
validate(): boolean {
this.errors = [];
console.log('开始表单验证...');
// 基础验证逻辑
for (const [key, value] of Object.entries(this.formData)) {
if (value === undefined || value === null || value === '') {
this.errors.push(`${key}不能为空`);
}
}
const isValid = this.errors.length === 0;
console.log(`验证结果:${isValid ? '通过' : '失败'}`);
if (!isValid) {
console.log('验证错误:', this.errors);
}
return isValid;
}
/**
* 获取验证错误
* @returns 错误列表
*/
getErrors(): string[] {
return [...this.errors];
}
}
// 通过命名空间为类添加静态功能
namespace FormValidator {
export const VERSION = '1.0.0';
export const SUPPORTED_TYPES = ['text', 'email', 'number', 'date'];
/**
* 验证邮箱格式
* @param email 邮箱地址
* @returns 是否有效
*/
export function validateEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const isValid = emailRegex.test(email);
console.log(`邮箱验证:${email} - ${isValid ? '有效' : '无效'}`);
return isValid;
}
/**
* 验证手机号格式
* @param phone 手机号
* @returns 是否有效
*/
export function validatePhone(phone: string): boolean {
const phoneRegex = /^1[3-9]\d{9}$/;
const isValid = phoneRegex.test(phone);
console.log(`手机号验证:${phone} - ${isValid ? '有效' : '无效'}`);
return isValid;
}
/**
* 创建预配置的验证器
* @param type 验证器类型
* @returns 验证器实例
*/
export function createValidator(type: 'user' | 'product' | 'order'): FormValidator {
console.log(`创建${type}验证器`);
const defaultData = {
user: { name: '', email: '', phone: '' },
product: { name: '', price: 0, category: '' },
order: { userId: '', productId: '', quantity: 1 }
};
return new FormValidator(defaultData[type]);
}
}
// 使用合并后的类和命名空间
console.log('=== 类与命名空间合并演示 ===');
// "=== 类与命名空间合并演示 ==="
// 访问命名空间的静态属性
console.log(`验证器版本:${FormValidator.VERSION}`); // "验证器版本:1.0.0"
console.log(`支持的类型:${FormValidator.SUPPORTED_TYPES.join(', ')}`);
// "支持的类型:text, email, number, date"
// 使用命名空间的静态方法
const email = 'user@example.com';
const phone = '13800138000';
const emailValid = FormValidator.validateEmail(email);
// "邮箱验证:user@example.com - 有效"
const phoneValid = FormValidator.validatePhone(phone);
// "手机号验证:13800138000 - 有效"
console.log(`邮箱${emailValid ? '有效' : '无效'},手机号${phoneValid ? '有效' : '无效'}`);
// "邮箱有效,手机号有效"
// 创建验证器实例
const userValidator = FormValidator.createValidator('user');
// "创建user验证器"
// "创建表单验证器"
// "表单数据:" { name: '', email: '', phone: '' }
// 验证空表单
const isValidEmpty = userValidator.validate();
// "开始表单验证..."
// "验证结果:失败"
// "验证错误:" ['name不能为空', 'email不能为空', 'phone不能为空']
console.log(`空表单验证:${isValidEmpty ? '通过' : '失败'}`); // "空表单验证:失败"
if (!isValidEmpty) {
const errors = userValidator.getErrors();
console.log(`错误数量:${errors.length}`);
// "错误数量:3"
}
// 创建有效的用户验证器
const validUserData = {
name: '张三',
email: 'zhangsan@example.com',
phone: '13800138000'
};
const validUserValidator = new FormValidator(validUserData);
// "创建表单验证器"
// "表单数据:" { name: '张三', email: 'zhangsan@example.com', phone: '13800138000' }
const isValidUser = validUserValidator.validate();
// "开始表单验证..."
// "验证结果:通过"
console.log(`有效表单验证:${isValidUser ? '通过' : '失败'}`); // "有效表单验证:通过"
🎯 声明合并的应用场景
合并类型 | 使用场景 | 优势 | 注意事项 |
---|---|---|---|
接口合并 | 扩展第三方库类型 | 类型安全的扩展 | 属性类型必须兼容 |
命名空间合并 | 模块化功能组织 | 逐步构建复杂功能 | 避免循环依赖 |
类与命名空间合并 | 为类添加静态功能 | 功能集中管理 | 保持职责清晰 |
8.5 三斜线指令——TypeScript的"老式电报" 📡
三斜线指令(Triple-Slash Directives)是TypeScript早期的模块导入语法,就像城市中的老式电报系统一样,虽然已被现代通信取代,但在特定场景下仍有其价值。
📜 基础三斜线指令:传统的"依赖声明"
// 📁 legacy-types.d.ts - 传统类型声明文件
/// <reference path="./user-types.d.ts" />
/// <reference path="./api-types.d.ts" />
/// <reference types="node" />
console.log('=== 三斜线指令演示 ===');
// "=== 三斜线指令演示 ==="
// 📁 user-types.d.ts - 用户类型声明
declare namespace UserTypes {
interface BasicUser {
id: string;
name: string;
email: string;
}
interface AdminUser extends BasicUser {
permissions: string[];
lastLogin: Date;
}
type UserRole = 'admin' | 'user' | 'guest';
}
// 📁 api-types.d.ts - API类型声明
declare namespace APITypes {
interface Response<T = any> {
success: boolean;
data: T;
message: string;
timestamp: string;
}
interface ErrorResponse {
success: false;
error: {
code: number;
message: string;
details?: any;
};
timestamp: string;
}
type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
}
// 📁 legacy-app.ts - 使用三斜线指令的应用
/// <reference path="./legacy-types.d.ts" />
/**
* 创建API响应
* @param data 响应数据
* @param message 响应消息
* @returns API响应对象
*/
function createApiResponse<T>(
data: T,
message: string = '操作成功'
): APITypes.Response<T> {
const response: APITypes.Response<T> = {
success: true,
data,
message,
timestamp: new Date().toISOString()
};
console.log(`创建API响应:${message}`);
console.log('响应数据:', response);
return response;
}
/**
* 创建错误响应
* @param code 错误代码
* @param message 错误消息
* @param details 错误详情
* @returns 错误响应对象
*/
function createErrorResponse(
code: number,
message: string,
details?: any
): APITypes.ErrorResponse {
const errorResponse: APITypes.ErrorResponse = {
success: false,
error: {
code,
message,
details
},
timestamp: new Date().toISOString()
};
console.log(`创建错误响应:${code} - ${message}`);
console.log('错误详情:', errorResponse.error);
return errorResponse;
}
/**
* 处理用户请求
* @param userData 用户数据
* @returns API响应
*/
function handleUserRequest(userData: UserTypes.BasicUser): APITypes.Response<UserTypes.BasicUser> {
console.log('处理用户请求');
try {
// 验证用户数据
if (!userData.id || !userData.name || !userData.email) {
throw new Error('用户数据不完整');
}
console.log(`处理用户:${userData.name}`);
return createApiResponse(userData, '用户处理成功');
// "创建API响应:用户处理成功"
// "响应数据:" { success: true, data: {...}, message: '用户处理成功', timestamp: '...' }
} catch (error) {
console.error('用户处理失败:', error);
return createErrorResponse(400, '用户数据无效', error) as any;
// "创建错误响应:400 - 用户数据无效"
// "错误详情:" { code: 400, message: '用户数据无效', details: Error }
}
}
// 使用三斜线指令的类型
const testUser: UserTypes.BasicUser = {
id: 'user_001',
name: '测试用户',
email: 'test@example.com'
};
const response = handleUserRequest(testUser);
// "处理用户请求"
// "处理用户:测试用户"
// "创建API响应:用户处理成功"
// "响应数据:" {...}
console.log(`请求处理结果:${response.success ? '成功' : '失败'}`);
// "请求处理结果:成功"
// 测试错误情况
const invalidUser = { id: '', name: '', email: '' } as UserTypes.BasicUser;
const errorResponse = handleUserRequest(invalidUser);
// "处理用户请求"
// "用户处理失败:" Error: 用户数据不完整
// "创建错误响应:400 - 用户数据无效"
// "错误详情:" {...}
console.log(`错误处理结果:${errorResponse.success ? '成功' : '失败'}`);
// "错误处理结果:失败"
🎯 三斜线指令的现代替代方案
// 📁 tsconfig.json - 现代配置方式
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node",
"types": ["node", "@types/lodash"],
"typeRoots": ["./node_modules/@types", "./src/types"],
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
// 📁 modern-approach.ts - 现代模块化方式
import type { User } from './types/user';
import type { APIResponse } from './types/api';
console.log('=== 现代模块化演示 ===');
// "=== 现代模块化演示 ==="
/**
* 现代化的用户处理函数
* @param user 用户对象
* @returns API响应
*/
function processUser(user: User): APIResponse<User> {
console.log(`现代化处理用户:${user.name}`);
const response: APIResponse<User> = {
success: true,
data: user,
message: '现代化处理成功',
timestamp: new Date().toISOString()
};
console.log('现代化响应:', response);
return response;
}
// 📁 src/types/user.ts - 现代类型定义
export interface User {
id: string;
name: string;
email: string;
role?: 'admin' | 'user' | 'guest';
}
export interface AdminUser extends User {
permissions: string[];
lastLogin: Date;
}
export type UserRole = 'admin' | 'user' | 'guest';
// 📁 src/types/api.ts - 现代API类型
export interface APIResponse<T = any> {
success: boolean;
data: T;
message: string;
timestamp: string;
}
export interface APIError {
code: number;
message: string;
details?: any;
}
export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
⚠️ 三斜线指令的使用建议
使用场景 | 推荐度 | 现代替代方案 |
---|---|---|
新项目 | ❌ 不推荐 | ES模块 + import/export |
类型声明文件 | ⚡ 可选 | 模块化类型定义 |
全局类型扩展 | ✅ 推荐 | declare global + 模块 |
旧项目维护 | ✅ 推荐 | 逐步迁移到ES模块 |
库的类型定义 | ⚡ 可选 | 现代声明文件格式 |
🏗️ 实战案例:构建模块化的任务管理系统
让我们通过一个完整的任务管理系统来演示模块化设计的最佳实践。
📁 项目结构设计
task-manager/
├── src/
│ ├── types/ # 类型定义
│ │ ├── index.ts
│ │ ├── task.ts
│ │ └── user.ts
│ ├── services/ # 业务服务
│ │ ├── index.ts
│ │ ├── taskService.ts
│ │ └── userService.ts
│ ├── utils/ # 工具函数
│ │ ├── index.ts
│ │ ├── validation.ts
│ │ └── formatting.ts
│ ├── components/ # 组件模块
│ │ ├── index.ts
│ │ ├── TaskList.ts
│ │ └── UserProfile.ts
│ └── app.ts # 应用入口
├── tsconfig.json
└── package.json
🎯 类型定义模块
// 📁 src/types/task.ts - 任务类型定义
export interface Task {
id: string;
title: string;
description: string;
status: TaskStatus;
priority: TaskPriority;
assigneeId: string;
createdAt: Date;
updatedAt: Date;
dueDate?: Date;
}
export type TaskStatus = 'pending' | 'in-progress' | 'completed' | 'cancelled';
export type TaskPriority = 'low' | 'medium' | 'high' | 'urgent';
export interface CreateTaskRequest {
title: string;
description: string;
priority: TaskPriority;
assigneeId: string;
dueDate?: Date;
}
export interface UpdateTaskRequest {
title?: string;
description?: string;
status?: TaskStatus;
priority?: TaskPriority;
dueDate?: Date;
}
export interface TaskFilter {
status?: TaskStatus;
priority?: TaskPriority;
assigneeId?: string;
dueBefore?: Date;
}
// 📁 src/types/user.ts - 用户类型定义
export interface User {
id: string;
name: string;
email: string;
role: UserRole;
department: string;
createdAt: Date;
}
export type UserRole = 'admin' | 'manager' | 'developer' | 'tester';
export interface CreateUserRequest {
name: string;
email: string;
role: UserRole;
department: string;
}
// 📁 src/types/index.ts - 类型入口文件
export * from './task';
export * from './user';
// 通用响应类型
export interface APIResponse<T = any> {
success: boolean;
data: T;
message: string;
timestamp: string;
}
export interface PaginatedResponse<T> extends APIResponse<T[]> {
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
};
}
🛠️ 服务层模块
// 📁 src/services/taskService.ts - 任务服务
import type {
Task,
CreateTaskRequest,
UpdateTaskRequest,
TaskFilter,
APIResponse,
PaginatedResponse
} from '@types';
import { generateId, formatDate } from '@utils';
import { validateTask } from '@utils/validation';
export class TaskService {
private tasks: Task[] = []; // 任务列表
/**
* 创建新任务
* @param request 创建任务请求
* @returns 创建的任务
*/
async createTask(request: CreateTaskRequest): Promise<APIResponse<Task>> {
console.log('创建新任务:', request.title);
try {
// 验证请求数据
const validation = validateTask(request);
if (!validation.isValid) {
console.log('任务验证失败:', validation.errors);
return {
success: false,
data: null as any,
message: `验证失败:${validation.errors.join(', ')}`,
timestamp: new Date().toISOString()
};
}
const task: Task = {
id: generateId('task'),
title: request.title,
description: request.description,
status: 'pending',
priority: request.priority,
assigneeId: request.assigneeId,
createdAt: new Date(),
updatedAt: new Date(),
dueDate: request.dueDate
};
this.tasks.push(task);
console.log(`任务创建成功:${task.id}`);
console.log(`当前任务总数:${this.tasks.length}`);
return {
success: true,
data: task,
message: '任务创建成功',
timestamp: new Date().toISOString()
};
} catch (error) {
console.error('创建任务失败:', error);
return {
success: false,
data: null as any,
message: '创建任务失败',
timestamp: new Date().toISOString()
};
}
}
/**
* 获取任务列表
* @param filter 过滤条件
* @param page 页码
* @param limit 每页数量
* @returns 分页任务列表
*/
async getTasks(
filter: TaskFilter = {},
page: number = 1,
limit: number = 10
): Promise<PaginatedResponse<Task>> {
console.log(`获取任务列表:页码${page},每页${limit}条`);
console.log('过滤条件:', filter);
let filteredTasks = this.tasks;
// 应用过滤条件
if (filter.status) {
filteredTasks = filteredTasks.filter(task => task.status === filter.status);
console.log(`状态过滤后:${filteredTasks.length}条`);
}
if (filter.priority) {
filteredTasks = filteredTasks.filter(task => task.priority === filter.priority);
console.log(`优先级过滤后:${filteredTasks.length}条`);
}
if (filter.assigneeId) {
filteredTasks = filteredTasks.filter(task => task.assigneeId === filter.assigneeId);
console.log(`负责人过滤后:${filteredTasks.length}条`);
}
// 分页处理
const total = filteredTasks.length;
const totalPages = Math.ceil(total / limit);
const startIndex = (page - 1) * limit;
const endIndex = startIndex + limit;
const paginatedTasks = filteredTasks.slice(startIndex, endIndex);
console.log(`分页结果:第${page}页,共${totalPages}页,当前页${paginatedTasks.length}条`);
return {
success: true,
data: paginatedTasks,
message: '获取任务列表成功',
timestamp: new Date().toISOString(),
pagination: {
page,
limit,
total,
totalPages
}
};
}
/**
* 更新任务
* @param taskId 任务ID
* @param updates 更新数据
* @returns 更新后的任务
*/
async updateTask(taskId: string, updates: UpdateTaskRequest): Promise<APIResponse<Task>> {
console.log(`更新任务:${taskId}`);
console.log('更新内容:', updates);
const taskIndex = this.tasks.findIndex(task => task.id === taskId);
if (taskIndex === -1) {
console.log(`任务不存在:${taskId}`);
return {
success: false,
data: null as any,
message: '任务不存在',
timestamp: new Date().toISOString()
};
}
const task = this.tasks[taskIndex];
const updatedTask: Task = {
...task,
...updates,
updatedAt: new Date()
};
this.tasks[taskIndex] = updatedTask;
console.log(`任务更新成功:${updatedTask.title}`);
return {
success: true,
data: updatedTask,
message: '任务更新成功',
timestamp: new Date().toISOString()
};
}
/**
* 删除任务
* @param taskId 任务ID
* @returns 删除结果
*/
async deleteTask(taskId: string): Promise<APIResponse<boolean>> {
console.log(`删除任务:${taskId}`);
const taskIndex = this.tasks.findIndex(task => task.id === taskId);
if (taskIndex === -1) {
console.log(`任务不存在:${taskId}`);
return {
success: false,
data: false,
message: '任务不存在',
timestamp: new Date().toISOString()
};
}
const deletedTask = this.tasks.splice(taskIndex, 1)[0];
console.log(`任务删除成功:${deletedTask.title}`);
console.log(`剩余任务数:${this.tasks.length}`);
return {
success: true,
data: true,
message: '任务删除成功',
timestamp: new Date().toISOString()
};
}
}
// 📁 src/services/userService.ts - 用户服务
import type { User, CreateUserRequest, APIResponse } from '@types';
import { generateId } from '@utils';
import { validateUser } from '@utils/validation';
export class UserService {
private users: User[] = [];
/**
* 创建用户
* @param request 创建用户请求
* @returns 创建的用户
*/
async createUser(request: CreateUserRequest): Promise<APIResponse<User>> {
console.log('创建新用户:', request.name);
try {
const validation = validateUser(request);
if (!validation.isValid) {
console.log('用户验证失败:', validation.errors);
return {
success: false,
data: null as any,
message: `验证失败:${validation.errors.join(', ')}`,
timestamp: new Date().toISOString()
};
}
const user: User = {
id: generateId('user'),
name: request.name,
email: request.email,
role: request.role,
department: request.department,
createdAt: new Date()
};
this.users.push(user);
console.log(`用户创建成功:${user.id}`);
console.log(`当前用户总数:${this.users.length}`);
return {
success: true,
data: user,
message: '用户创建成功',
timestamp: new Date().toISOString()
};
} catch (error) {
console.error('创建用户失败:', error);
return {
success: false,
data: null as any,
message: '创建用户失败',
timestamp: new Date().toISOString()
};
}
}
/**
* 获取所有用户
* @returns 用户列表
*/
async getUsers(): Promise<APIResponse<User[]>> {
console.log(`获取所有用户,共${this.users.length}个`);
return {
success: true,
data: [...this.users],
message: '获取用户列表成功',
timestamp: new Date().toISOString()
};
}
/**
* 根据ID获取用户
* @param userId 用户ID
* @returns 用户信息
*/
async getUserById(userId: string): Promise<APIResponse<User>> {
console.log(`获取用户:${userId}`);
const user = this.users.find(u => u.id === userId);
if (!user) {
console.log(`用户不存在:${userId}`);
return {
success: false,
data: null as any,
message: '用户不存在',
timestamp: new Date().toISOString()
};
}
console.log(`找到用户:${user.name}`);
return {
success: true,
data: user,
message: '获取用户成功',
timestamp: new Date().toISOString()
};
}
}
// 📁 src/services/index.ts - 服务入口
export { TaskService } from './taskService';
export { UserService } from './userService';
// 创建服务实例
export const taskService = new TaskService();
export const userService = new UserService();
🔧 工具函数模块
// 📁 src/utils/validation.ts - 验证工具
import type { CreateTaskRequest, CreateUserRequest } from '@types';
export interface ValidationResult {
isValid: boolean;
errors: string[];
}
/**
* 验证任务数据
* @param task 任务数据
* @returns 验证结果
*/
export function validateTask(task: CreateTaskRequest): ValidationResult {
const errors: string[] = [];
console.log('验证任务数据:', task.title);
if (!task.title || task.title.trim().length === 0) {
errors.push('任务标题不能为空');
}
if (task.title && task.title.length > 100) {
errors.push('任务标题不能超过100个字符');
}
if (!task.description || task.description.trim().length === 0) {
errors.push('任务描述不能为空');
}
if (!task.assigneeId || task.assigneeId.trim().length === 0) {
errors.push('必须指定任务负责人');
}
if (!['low', 'medium', 'high', 'urgent'].includes(task.priority)) {
errors.push('任务优先级无效');
}
if (task.dueDate && task.dueDate < new Date()) {
errors.push('截止日期不能早于当前时间');
}
const isValid = errors.length === 0;
console.log(`任务验证结果:${isValid ? '通过' : '失败'}`);
if (!isValid) {
console.log('验证错误:', errors);
}
return { isValid, errors };
}
/**
* 验证用户数据
* @param user 用户数据
* @returns 验证结果
*/
export function validateUser(user: CreateUserRequest): ValidationResult {
const errors: string[] = [];
console.log('验证用户数据:', user.name);
if (!user.name || user.name.trim().length === 0) {
errors.push('用户名不能为空');
}
if (user.name && user.name.length > 50) {
errors.push('用户名不能超过50个字符');
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!user.email || !emailRegex.test(user.email)) {
errors.push('邮箱格式无效');
}
if (!['admin', 'manager', 'developer', 'tester'].includes(user.role)) {
errors.push('用户角色无效');
}
if (!user.department || user.department.trim().length === 0) {
errors.push('部门不能为空');
}
const isValid = errors.length === 0;
console.log(`用户验证结果:${isValid ? '通过' : '失败'}`);
if (!isValid) {
console.log('验证错误:', errors);
}
return { isValid, errors };
}
// 📁 src/utils/formatting.ts - 格式化工具
import type { Task, User, TaskStatus, TaskPriority } from '@types';
/**
* 格式化日期
* @param date 日期对象
* @returns 格式化的日期字符串
*/
export function formatDate(date: Date): string {
const formatted = date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
console.log(`格式化日期:${date.toISOString()} -> ${formatted}`);
return formatted;
}
/**
* 格式化任务状态
* @param status 任务状态
* @returns 中文状态描述
*/
export function formatTaskStatus(status: TaskStatus): string {
const statusMap = {
'pending': '待处理',
'in-progress': '进行中',
'completed': '已完成',
'cancelled': '已取消'
};
const formatted = statusMap[status] || '未知状态';
console.log(`格式化任务状态:${status} -> ${formatted}`);
return formatted;
}
/**
* 格式化任务优先级
* @param priority 任务优先级
* @returns 中文优先级描述
*/
export function formatTaskPriority(priority: TaskPriority): string {
const priorityMap = {
'low': '低',
'medium': '中',
'high': '高',
'urgent': '紧急'
};
const formatted = priorityMap[priority] || '未知优先级';
console.log(`格式化任务优先级:${priority} -> ${formatted}`);
return formatted;
}
/**
* 生成唯一ID
* @param prefix 前缀
* @returns 唯一ID
*/
export function generateId(prefix: string = 'id'): string {
const timestamp = Date.now();
const random = Math.random().toString(36).substr(2, 8);
const id = `${prefix}_${timestamp}_${random}`;
console.log(`生成ID:${id}`);
return id;
}
/**
* 格式化任务摘要
* @param task 任务对象
* @returns 任务摘要字符串
*/
export function formatTaskSummary(task: Task): string {
const status = formatTaskStatus(task.status);
const priority = formatTaskPriority(task.priority);
const dueDate = task.dueDate ? formatDate(task.dueDate) : '无截止日期';
const summary = `[${status}] ${task.title} (优先级:${priority},截止:${dueDate})`;
console.log(`格式化任务摘要:${summary}`);
return summary;
}
// 📁 src/utils/index.ts - 工具入口
export * from './validation';
export * from './formatting';
// 通用工具函数
/**
* 延迟执行
* @param ms 延迟毫秒数
* @returns Promise
*/
export function delay(ms: number): Promise<void> {
console.log(`开始延迟 ${ms}ms`);
return new Promise(resolve => {
setTimeout(() => {
console.log(`延迟 ${ms}ms 完成`);
resolve();
}, ms);
});
}
/**
* 安全的JSON解析
* @param jsonString JSON字符串
* @param defaultValue 默认值
* @returns 解析结果
*/
export function safeJsonParse<T>(jsonString: string, defaultValue: T): T {
try {
const result = JSON.parse(jsonString);
console.log('JSON解析成功');
return result;
} catch (error) {
console.log('JSON解析失败,使用默认值');
return defaultValue;
}
}
🎮 应用入口演示
// 📁 src/app.ts - 应用入口
import { taskService, userService } from '@services';
import { formatTaskSummary, delay } from '@utils';
import type { CreateTaskRequest, CreateUserRequest } from '@types';
console.log('=== 任务管理系统演示 ===');
// "=== 任务管理系统演示 ==="
/**
* 演示完整的任务管理流程
*/
async function demonstrateTaskManagement() {
console.log('\n--- 1. 创建用户 ---');
// "--- 1. 创建用户 ---"
// 创建用户
const createUserRequest: CreateUserRequest = {
name: '张三',
email: 'zhangsan@example.com',
role: 'developer',
department: '技术部'
};
const userResponse = await userService.createUser(createUserRequest);
// "验证用户数据:张三"
// "用户验证结果:通过"
// "生成ID:user_1704067200000_abc12345"
// "创建新用户:张三"
// "用户创建成功:user_1704067200000_abc12345"
// "当前用户总数:1"
if (!userResponse.success) {
console.error('用户创建失败:', userResponse.message);
return;
}
const user = userResponse.data;
console.log(`用户创建成功:${user.name} (${user.id})`);
// "用户创建成功:张三 (user_1704067200000_abc12345)"
console.log('\n--- 2. 创建任务 ---');
// "--- 2. 创建任务 ---"
// 创建任务
const createTaskRequest: CreateTaskRequest = {
title: '实现用户登录功能',
description: '开发用户登录页面,包括表单验证和身份认证',
priority: 'high',
assigneeId: user.id,
dueDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7天后
};
const taskResponse = await taskService.createTask(createTaskRequest);
// "验证任务数据:实现用户登录功能"
// "任务验证结果:通过"
// "生成ID:task_1704067200001_def67890"
// "创建新任务:实现用户登录功能"
// "任务创建成功:task_1704067200001_def67890"
// "当前任务总数:1"
if (!taskResponse.success) {
console.error('任务创建失败:', taskResponse.message);
return;
}
const task = taskResponse.data;
console.log(`任务创建成功:${task.title} (${task.id})`);
// "任务创建成功:实现用户登录功能 (task_1704067200001_def67890)"
// 格式化任务摘要
const taskSummary = formatTaskSummary(task);
// "格式化任务状态:pending -> 待处理"
// "格式化任务优先级:high -> 高"
// "格式化日期:2024-01-08T12:00:00.000Z -> 2024/01/08"
// "格式化任务摘要:[待处理] 实现用户登录功能 (优先级:高,截止:2024/01/08)"
console.log(`任务摘要:${taskSummary}`);
// "任务摘要:[待处理] 实现用户登录功能 (优先级:高,截止:2024/01/08)"
console.log('\n--- 3. 更新任务状态 ---');
// "--- 3. 更新任务状态 ---"
// 模拟任务进度
await delay(1000);
// "开始延迟 1000ms"
// (1秒后)
// "延迟 1000ms 完成"
const updateResponse = await taskService.updateTask(task.id, {
status: 'in-progress'
});
// "更新任务:task_1704067200001_def67890"
// "更新内容:" { status: 'in-progress' }
// "任务更新成功:实现用户登录功能"
if (updateResponse.success) {
const updatedTask = updateResponse.data;
const updatedSummary = formatTaskSummary(updatedTask);
// "格式化任务状态:in-progress -> 进行中"
// "格式化任务优先级:high -> 高"
// "格式化日期:2024-01-08T12:00:00.000Z -> 2024/01/08"
// "格式化任务摘要:[进行中] 实现用户登录功能 (优先级:高,截止:2024/01/08)"
console.log(`任务状态已更新:${updatedSummary}`);
// "任务状态已更新:[进行中] 实现用户登录功能 (优先级:高,截止:2024/01/08)"
}
console.log('\n--- 4. 查询任务列表 ---');
// "--- 4. 查询任务列表 ---"
const tasksResponse = await taskService.getTasks(
{ status: 'in-progress' },
1,
5
);
// "获取任务列表:页码1,每页5条"
// "过滤条件:" { status: 'in-progress' }
// "状态过滤后:1条"
// "分页结果:第1页,共1页,当前页1条"
if (tasksResponse.success) {
console.log(`找到 ${tasksResponse.data.length} 个进行中的任务`);
// "找到 1 个进行中的任务"
tasksResponse.data.forEach((task, index) => {
const summary = formatTaskSummary(task);
console.log(`${index + 1}. ${summary}`);
// "格式化任务状态:in-progress -> 进行中"
// "格式化任务优先级:high -> 高"
// "格式化日期:2024-01-08T12:00:00.000Z -> 2024/01/08"
// "格式化任务摘要:[进行中] 实现用户登录功能 (优先级:高,截止:2024/01/08)"
// "1. [进行中] 实现用户登录功能 (优先级:高,截止:2024/01/08)"
});
}
console.log('\n--- 5. 完成任务 ---');
// "--- 5. 完成任务 ---"
await delay(2000);
// "开始延迟 2000ms"
// (2秒后)
// "延迟 2000ms 完成"
const completeResponse = await taskService.updateTask(task.id, {
status: 'completed'
});
// "更新任务:task_1704067200001_def67890"
// "更新内容:" { status: 'completed' }
// "任务更新成功:实现用户登录功能"
if (completeResponse.success) {
const completedTask = completeResponse.data;
const completedSummary = formatTaskSummary(completedTask);
// "格式化任务状态:completed -> 已完成"
// "格式化任务优先级:high -> 高"
// "格式化日期:2024-01-08T12:00:00.000Z -> 2024/01/08"
// "格式化任务摘要:[已完成] 实现用户登录功能 (优先级:高,截止:2024/01/08)"
console.log(`任务已完成:${completedSummary}`);
// "任务已完成:[已完成] 实现用户登录功能 (优先级:高,截止:2024/01/08)"
}
console.log('\n--- 演示完成 ---');
// "--- 演示完成 ---"
}
// 运行演示
demonstrateTaskManagement().catch(error => {
console.error('演示过程中发生错误:', error);
});
🎯 模块化设计的核心收益
设计原则 | 实现方式 | 带来的好处 |
---|---|---|
单一职责 | 每个模块专注特定功能 | 代码清晰,易于维护 |
依赖注入 | 通过import明确依赖 | 便于测试和替换 |
类型安全 | 统一的类型定义 | 减少运行时错误 |
可扩展性 | 模块化的服务层 | 易于添加新功能 |
可重用性 | 通用的工具函数 | 提高开发效率 |
📋 本章核心收获
🎯 关键概念掌握
-
ES模块系统:现代JavaScript的标准模块化方案
import/export
语法的灵活运用- 动态导入实现按需加载
- 模块作用域隔离避免全局污染
-
命名空间:TypeScript的传统代码组织方式
- 适用于特定场景(全局脚本、类型声明)
- 嵌套命名空间实现层次化管理
- 与现代模块系统的对比选择
-
模块解析策略:编译器的"导航系统"
- Node.js风格的解析算法
- 路径别名简化导入路径
- 解析顺序的深入理解
-
声明合并:TypeScript的独特功能
- 接口合并扩展第三方库
- 命名空间合并组织复杂功能
- 类与命名空间合并增强静态功能
-
三斜线指令:传统的依赖声明方式
- 在特定场景下的价值
- 与现代模块系统的迁移策略
🛠️ 实践技能提升
- 项目结构设计:合理的目录组织
- 类型系统规划:统一的类型定义管理
- 服务层架构:模块化的业务逻辑组织
- 工具函数封装:可重用的通用功能
- 配置文件优化:TypeScript编译选项调优
🎨 设计模式应用
- 模块模式:封装和暴露接口
- 工厂模式:服务实例的创建管理
- 策略模式:不同解析策略的选择
- 装饰器模式:功能的渐进式增强
🚀 最佳实践总结
- 优先使用ES模块:拥抱现代标准
- 合理设计目录结构:便于维护和扩展
- 统一类型定义:提高代码一致性
- 配置路径别名:简化导入路径
- 渐进式迁移:从旧系统平滑过渡
🎯 进阶学习方向
- 微前端架构:大型应用的模块化拆分
- 模块联邦:跨应用的模块共享
- Tree Shaking优化:减少打包体积
- 代码分割策略:提升加载性能
- 模块热替换:提升开发体验
🎉 恭喜你! 你已经掌握了TypeScript模块化开发的精髓,就像一位经验丰富的城市规划师,能够设计出既美观又实用的代码"城市"。下一章我们将进入装饰器的奇妙世界,学习如何通过装饰器为代码添加"魔法"般的增强功能!