TypeScript_学习资料_综合实战项目

24 阅读7分钟

TypeScript 综合实战项目

目录

  1. 项目一:Todo 应用
  2. 项目二:用户管理系统
  3. 项目三:电商购物车
  4. 项目四:博客系统
  5. 项目五:实时聊天应用

项目一:Todo 应用

项目概述

一个功能完整的 Todo 应用,包含任务的增删改查、分类、优先级、截止日期等功能。

类型定义

// 枚举定义
enum Priority {
    Low = 'low',
    Medium = 'medium',
    High = 'high',
    Urgent = 'urgent'
}

enum Status {
    Pending = 'pending',
    InProgress = 'in-progress',
    Completed = 'completed',
    Cancelled = 'cancelled'
}

// 基础接口
interface Todo {
    id: string;
    title: string;
    description?: string;
    priority: Priority;
    status: Status;
    category?: string;
    tags: string[];
    dueDate?: Date;
    createdAt: Date;
    updatedAt: Date;
    completedAt?: Date;
}

interface Category {
    id: string;
    name: string;
    color: string;
    icon?: string;
}

interface TodoFilter {
    status?: Status[];
    priority?: Priority[];
    category?: string;
    tags?: string[];
    searchText?: string;
    dueDateFrom?: Date;
    dueDateTo?: Date;
}

interface TodoStats {
    total: number;
    pending: number;
    inProgress: number;
    completed: number;
    cancelled: number;
    overdue: number;
}

服务层实现

// Todo 服务接口
interface ITodoService {
    // CRUD 操作
    createTodo(todo: Omit<Todo, 'id' | 'createdAt' | 'updatedAt'>): Todo;
    getTodo(id: string): Todo | undefined;
    getAllTodos(): Todo[];
    updateTodo(id: string, updates: Partial<Todo>): Todo;
    deleteTodo(id: string): boolean;
    
    // 查询操作
    filterTodos(filter: TodoFilter): Todo[];
    searchTodos(keyword: string): Todo[];
    getTodosByCategory(categoryId: string): Todo[];
    getTodosByStatus(status: Status): Todo[];
    getOverdueTodos(): Todo[];
    
    // 统计操作
    getStats(): TodoStats;
    
    // 批量操作
    bulkUpdateStatus(ids: string[], status: Status): Todo[];
    bulkDelete(ids: string[]): boolean;
}

// Todo 服务实现
class TodoService implements ITodoService {
    private todos: Map<string, Todo> = new Map();
    private categories: Map<string, Category> = new Map();
    
    createTodo(todoData: Omit<Todo, 'id' | 'createdAt' | 'updatedAt'>): Todo {
        const todo: Todo = {
            ...todoData,
            id: this.generateId(),
            createdAt: new Date(),
            updatedAt: new Date()
        };
        
        this.todos.set(todo.id, todo);
        return todo;
    }
    
    getTodo(id: string): Todo | undefined {
        return this.todos.get(id);
    }
    
    getAllTodos(): Todo[] {
        return Array.from(this.todos.values());
    }
    
    updateTodo(id: string, updates: Partial<Todo>): Todo {
        const todo = this.todos.get(id);
        if (!todo) {
            throw new Error(`Todo with id ${id} not found`);
        }
        
        const updatedTodo: Todo = {
            ...todo,
            ...updates,
            updatedAt: new Date()
        };
        
        // 如果状态变为已完成,设置完成时间
        if (updates.status === Status.Completed && todo.status !== Status.Completed) {
            updatedTodo.completedAt = new Date();
        }
        
        this.todos.set(id, updatedTodo);
        return updatedTodo;
    }
    
    deleteTodo(id: string): boolean {
        return this.todos.delete(id);
    }
    
    filterTodos(filter: TodoFilter): Todo[] {
        let todos = this.getAllTodos();
        
        if (filter.status) {
            todos = todos.filter(todo => filter.status!.includes(todo.status));
        }
        
        if (filter.priority) {
            todos = todos.filter(todo => filter.priority!.includes(todo.priority));
        }
        
        if (filter.category) {
            todos = todos.filter(todo => todo.category === filter.category);
        }
        
        if (filter.tags && filter.tags.length > 0) {
            todos = todos.filter(todo => 
                filter.tags!.some(tag => todo.tags.includes(tag))
            );
        }
        
        if (filter.searchText) {
            const searchLower = filter.searchText.toLowerCase();
            todos = todos.filter(todo => 
                todo.title.toLowerCase().includes(searchLower) ||
                (todo.description && todo.description.toLowerCase().includes(searchLower))
            );
        }
        
        if (filter.dueDateFrom) {
            todos = todos.filter(todo => 
                todo.dueDate && todo.dueDate >= filter.dueDateFrom!
            );
        }
        
        if (filter.dueDateTo) {
            todos = todos.filter(todo => 
                todo.dueDate && todo.dueDate <= filter.dueDateTo!
            );
        }
        
        return todos;
    }
    
    searchTodos(keyword: string): Todo[] {
        return this.filterTodos({ searchText: keyword });
    }
    
    getTodosByCategory(categoryId: string): Todo[] {
        return this.filterTodos({ category: categoryId });
    }
    
    getTodosByStatus(status: Status): Todo[] {
        return this.filterTodos({ status: [status] });
    }
    
    getOverdueTodos(): Todo[] {
        const now = new Date();
        return this.getAllTodos().filter(todo => 
            todo.status !== Status.Completed &&
            todo.status !== Status.Cancelled &&
            todo.dueDate &&
            todo.dueDate < now
        );
    }
    
    getStats(): TodoStats {
        const todos = this.getAllTodos();
        const overdueTodos = this.getOverdueTodos();
        
        return {
            total: todos.length,
            pending: todos.filter(t => t.status === Status.Pending).length,
            inProgress: todos.filter(t => t.status === Status.InProgress).length,
            completed: todos.filter(t => t.status === Status.Completed).length,
            cancelled: todos.filter(t => t.status === Status.Cancelled).length,
            overdue: overdueTodos.length
        };
    }
    
    bulkUpdateStatus(ids: string[], status: Status): Todo[] {
        return ids.map(id => this.updateTodo(id, { status }));
    }
    
    bulkDelete(ids: string[]): boolean {
        let allDeleted = true;
        ids.forEach(id => {
            if (!this.deleteTodo(id)) {
                allDeleted = false;
            }
        });
        return allDeleted;
    }
    
    private generateId(): string {
        return `todo_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }
}

使用示例

// 创建 Todo 服务实例
const todoService = new TodoService();

// 创建 Todo
const todo1 = todoService.createTodo({
    title: '学习 TypeScript',
    description: '完成 TypeScript 学习资料的阅读',
    priority: Priority.High,
    status: Status.InProgress,
    tags: ['学习', '编程'],
    dueDate: new Date('2024-12-31')
});

const todo2 = todoService.createTodo({
    title: '完成项目文档',
    priority: Priority.Medium,
    status: Status.Pending,
    tags: ['工作', '文档'],
    dueDate: new Date('2024-12-15')
});

// 查询 Todo
const allTodos = todoService.getAllTodos();
console.log('所有任务:', allTodos);

// 过滤 Todo
const highPriorityTodos = todoService.filterTodos({
    priority: [Priority.High, Priority.Urgent]
});
console.log('高优先级任务:', highPriorityTodos);

// 搜索 Todo
const searchResults = todoService.searchTodos('TypeScript');
console.log('搜索结果:', searchResults);

// 获取统计信息
const stats = todoService.getStats();
console.log('任务统计:', stats);

// 更新 Todo
todoService.updateTodo(todo1.id, {
    status: Status.Completed
});

// 获取逾期任务
const overdueTodos = todoService.getOverdueTodos();
console.log('逾期任务:', overdueTodos);

// 批量更新状态
todoService.bulkUpdateStatus([todo1.id, todo2.id], Status.Completed);

项目二:用户管理系统

项目概述

一个完整的用户管理系统,包含用户认证、角色权限、用户资料管理等功能。

类型定义

// 用户角色和权限
enum UserRole {
    SuperAdmin = 'super-admin',
    Admin = 'admin',
    Manager = 'manager',
    User = 'user',
    Guest = 'guest'
}

enum Permission {
    // 用户管理
    UserRead = 'user:read',
    UserWrite = 'user:write',
    UserDelete = 'user:delete',
    
    // 角色管理
    RoleRead = 'role:read',
    RoleWrite = 'role:write',
    RoleDelete = 'role:delete',
    
    // 系统管理
    SystemConfig = 'system:config',
    SystemLogs = 'system:logs',
    
    // 内容管理
    ContentRead = 'content:read',
    ContentWrite = 'content:write',
    ContentPublish = 'content:publish',
    ContentDelete = 'content:delete'
}

// 用户接口
interface User {
    id: number;
    username: string;
    email: string;
    passwordHash: string;
    role: UserRole;
    profile: UserProfile;
    status: UserStatus;
    permissions: Permission[];
    createdAt: Date;
    updatedAt: Date;
    lastLoginAt?: Date;
}

interface UserProfile {
    firstName: string;
    lastName: string;
    avatar?: string;
    phone?: string;
    bio?: string;
    address?: Address;
}

interface Address {
    street: string;
    city: string;
    state: string;
    zipCode: string;
    country: string;
}

enum UserStatus {
    Active = 'active',
    Inactive = 'inactive',
    Suspended = 'suspended',
    Deleted = 'deleted'
}

// 认证相关
interface AuthCredentials {
    username: string;
    password: string;
}

interface AuthToken {
    accessToken: string;
    refreshToken: string;
    expiresIn: number;
    tokenType: 'Bearer';
}

interface AuthSession {
    userId: number;
    token: string;
    expiresAt: Date;
    createdAt: Date;
}

// 注册数据
interface RegisterData {
    username: string;
    email: string;
    password: string;
    firstName: string;
    lastName: string;
}

// 用户查询过滤
interface UserFilter {
    role?: UserRole[];
    status?: UserStatus[];
    searchText?: string;
    createdFrom?: Date;
    createdTo?: Date;
}

认证服务实现

// 认证服务接口
interface IAuthService {
    register(data: RegisterData): Promise<User>;
    login(credentials: AuthCredentials): Promise<{ user: User; token: AuthToken }>;
    logout(userId: number): Promise<void>;
    refreshToken(refreshToken: string): Promise<AuthToken>;
    verifyToken(token: string): Promise<User | null>;
    changePassword(userId: number, oldPassword: string, newPassword: string): Promise<boolean>;
    resetPassword(email: string): Promise<boolean>;
}

// 认证服务实现
class AuthService implements IAuthService {
    private users: Map<number, User> = new Map();
    private sessions: Map<string, AuthSession> = new Map();
    private nextUserId = 1;
    
    async register(data: RegisterData): Promise<User> {
        // 检查用户名是否已存在
        const existingUser = Array.from(this.users.values()).find(
            u => u.username === data.username || u.email === data.email
        );
        
        if (existingUser) {
            throw new Error('用户名或邮箱已存在');
        }
        
        // 创建新用户
        const user: User = {
            id: this.nextUserId++,
            username: data.username,
            email: data.email,
            passwordHash: await this.hashPassword(data.password),
            role: UserRole.User,
            profile: {
                firstName: data.firstName,
                lastName: data.lastName
            },
            status: UserStatus.Active,
            permissions: this.getDefaultPermissions(UserRole.User),
            createdAt: new Date(),
            updatedAt: new Date()
        };
        
        this.users.set(user.id, user);
        return this.sanitizeUser(user);
    }
    
    async login(credentials: AuthCredentials): Promise<{ user: User; token: AuthToken }> {
        // 查找用户
        const user = Array.from(this.users.values()).find(
            u => u.username === credentials.username
        );
        
        if (!user) {
            throw new Error('用户名或密码错误');
        }
        
        // 验证密码
        const isValidPassword = await this.verifyPassword(
            credentials.password,
            user.passwordHash
        );
        
        if (!isValidPassword) {
            throw new Error('用户名或密码错误');
        }
        
        // 检查用户状态
        if (user.status !== UserStatus.Active) {
            throw new Error('用户账号已被禁用');
        }
        
        // 生成令牌
        const token = this.generateToken(user);
        
        // 创建会话
        const session: AuthSession = {
            userId: user.id,
            token: token.accessToken,
            expiresAt: new Date(Date.now() + token.expiresIn * 1000),
            createdAt: new Date()
        };
        this.sessions.set(token.accessToken, session);
        
        // 更新最后登录时间
        user.lastLoginAt = new Date();
        user.updatedAt = new Date();
        
        return {
            user: this.sanitizeUser(user),
            token
        };
    }
    
    async logout(userId: number): Promise<void> {
        // 删除用户的所有会话
        for (const [token, session] of this.sessions.entries()) {
            if (session.userId === userId) {
                this.sessions.delete(token);
            }
        }
    }
    
    async refreshToken(refreshToken: string): Promise<AuthToken> {
        // 验证刷新令牌并生成新的访问令牌
        const session = this.sessions.get(refreshToken);
        if (!session || session.expiresAt < new Date()) {
            throw new Error('刷新令牌无效或已过期');
        }
        
        const user = this.users.get(session.userId);
        if (!user) {
            throw new Error('用户不存在');
        }
        
        return this.generateToken(user);
    }
    
    async verifyToken(token: string): Promise<User | null> {
        const session = this.sessions.get(token);
        if (!session || session.expiresAt < new Date()) {
            return null;
        }
        
        const user = this.users.get(session.userId);
        return user ? this.sanitizeUser(user) : null;
    }
    
    async changePassword(
        userId: number,
        oldPassword: string,
        newPassword: string
    ): Promise<boolean> {
        const user = this.users.get(userId);
        if (!user) {
            throw new Error('用户不存在');
        }
        
        const isValidPassword = await this.verifyPassword(
            oldPassword,
            user.passwordHash
        );
        
        if (!isValidPassword) {
            throw new Error('当前密码错误');
        }
        
        user.passwordHash = await this.hashPassword(newPassword);
        user.updatedAt = new Date();
        
        // 使所有会话失效
        await this.logout(userId);
        
        return true;
    }
    
    async resetPassword(email: string): Promise<boolean> {
        const user = Array.from(this.users.values()).find(
            u => u.email === email
        );
        
        if (!user) {
            // 为了安全,即使用户不存在也返回 true
            return true;
        }
        
        // 在实际应用中,这里会发送重置密码的邮件
        console.log(`发送密码重置邮件到: ${email}`);
        
        return true;
    }
    
    private async hashPassword(password: string): Promise<string> {
        // 实际应用中应使用 bcrypt 等安全的哈希算法
        return `hashed_${password}`;
    }
    
    private async verifyPassword(password: string, hash: string): Promise<boolean> {
        // 实际应用中应使用 bcrypt 验证
        return hash === `hashed_${password}`;
    }
    
    private generateToken(user: User): AuthToken {
        const accessToken = `access_${user.id}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        const refreshToken = `refresh_${user.id}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        
        return {
            accessToken,
            refreshToken,
            expiresIn: 3600, // 1 hour
            tokenType: 'Bearer'
        };
    }
    
    private getDefaultPermissions(role: UserRole): Permission[] {
        const permissionMap: Record<UserRole, Permission[]> = {
            [UserRole.SuperAdmin]: Object.values(Permission),
            [UserRole.Admin]: [
                Permission.UserRead,
                Permission.UserWrite,
                Permission.RoleRead,
                Permission.ContentRead,
                Permission.ContentWrite,
                Permission.ContentPublish
            ],
            [UserRole.Manager]: [
                Permission.UserRead,
                Permission.ContentRead,
                Permission.ContentWrite,
                Permission.ContentPublish
            ],
            [UserRole.User]: [
                Permission.ContentRead
            ],
            [UserRole.Guest]: [
                Permission.ContentRead
            ]
        };
        
        return permissionMap[role] || [];
    }
    
    private sanitizeUser(user: User): User {
        // 移除敏感信息
        const { passwordHash, ...sanitized } = user;
        return sanitized as User;
    }
}

用户服务实现

// 用户服务接口
interface IUserService {
    getUser(id: number): User | undefined;
    getAllUsers(): User[];
    updateUser(id: number, updates: Partial<User>): User;
    deleteUser(id: number): boolean;
    filterUsers(filter: UserFilter): User[];
    updateUserRole(id: number, role: UserRole): User;
    updateUserStatus(id: number, status: UserStatus): User;
    grantPermissions(id: number, permissions: Permission[]): User;
    revokePermissions(id: number, permissions: Permission[]): User;
    hasPermission(userId: number, permission: Permission): boolean;
}

// 用户服务实现
class UserService implements IUserService {
    constructor(private authService: AuthService) {}
    
    getUser(id: number): User | undefined {
        // 实现从 authService 获取用户
        return undefined;
    }
    
    getAllUsers(): User[] {
        // 实现获取所有用户
        return [];
    }
    
    updateUser(id: number, updates: Partial<User>): User {
        const user = this.getUser(id);
        if (!user) {
            throw new Error('用户不存在');
        }
        
        // 不允许直接更新敏感字段
        const { passwordHash, id: _, ...allowedUpdates } = updates as any;
        
        const updatedUser = {
            ...user,
            ...allowedUpdates,
            updatedAt: new Date()
        };
        
        return updatedUser;
    }
    
    deleteUser(id: number): boolean {
        const user = this.getUser(id);
        if (!user) {
            return false;
        }
        
        // 软删除:更改用户状态
        this.updateUserStatus(id, UserStatus.Deleted);
        return true;
    }
    
    filterUsers(filter: UserFilter): User[] {
        let users = this.getAllUsers();
        
        if (filter.role) {
            users = users.filter(u => filter.role!.includes(u.role));
        }
        
        if (filter.status) {
            users = users.filter(u => filter.status!.includes(u.status));
        }
        
        if (filter.searchText) {
            const searchLower = filter.searchText.toLowerCase();
            users = users.filter(u => 
                u.username.toLowerCase().includes(searchLower) ||
                u.email.toLowerCase().includes(searchLower) ||
                u.profile.firstName.toLowerCase().includes(searchLower) ||
                u.profile.lastName.toLowerCase().includes(searchLower)
            );
        }
        
        return users;
    }
    
    updateUserRole(id: number, role: UserRole): User {
        return this.updateUser(id, { role });
    }
    
    updateUserStatus(id: number, status: UserStatus): User {
        return this.updateUser(id, { status });
    }
    
    grantPermissions(id: number, permissions: Permission[]): User {
        const user = this.getUser(id);
        if (!user) {
            throw new Error('用户不存在');
        }
        
        const newPermissions = Array.from(
            new Set([...user.permissions, ...permissions])
        );
        
        return this.updateUser(id, { permissions: newPermissions });
    }
    
    revokePermissions(id: number, permissions: Permission[]): User {
        const user = this.getUser(id);
        if (!user) {
            throw new Error('用户不存在');
        }
        
        const newPermissions = user.permissions.filter(
            p => !permissions.includes(p)
        );
        
        return this.updateUser(id, { permissions: newPermissions });
    }
    
    hasPermission(userId: number, permission: Permission): boolean {
        const user = this.getUser(userId);
        if (!user || user.status !== UserStatus.Active) {
            return false;
        }
        
        return user.permissions.includes(permission);
    }
}

使用示例

// 创建服务实例
const authService = new AuthService();
const userService = new UserService(authService);

// 用户注册
async function registerExample() {
    try {
        const newUser = await authService.register({
            username: 'zhangsan',
            email: 'zhangsan@example.com',
            password: 'Password123!',
            firstName: '张',
            lastName: '三'
        });
        
        console.log('注册成功:', newUser);
    } catch (error) {
        console.error('注册失败:', error);
    }
}

// 用户登录
async function loginExample() {
    try {
        const result = await authService.login({
            username: 'zhangsan',
            password: 'Password123!'
        });
        
        console.log('登录成功:', result.user);
        console.log('访问令牌:', result.token.accessToken);
        
        // 保存令牌以供后续请求使用
        localStorage.setItem('accessToken', result.token.accessToken);
    } catch (error) {
        console.error('登录失败:', error);
    }
}

// 验证令牌
async function verifyTokenExample() {
    const token = localStorage.getItem('accessToken');
    if (!token) {
        console.log('未登录');
        return;
    }
    
    const user = await authService.verifyToken(token);
    if (user) {
        console.log('当前用户:', user);
    } else {
        console.log('令牌无效');
        localStorage.removeItem('accessToken');
    }
}

// 权限检查
function checkPermissionExample(userId: number) {
    const canWrite = userService.hasPermission(userId, Permission.ContentWrite);
    const canDelete = userService.hasPermission(userId, Permission.ContentDelete);
    
    console.log('是否有写权限:', canWrite);
    console.log('是否有删除权限:', canDelete);
}

项目三:电商购物车

项目概述

一个功能完整的电商购物车系统,包含商品管理、购物车、订单、支付等功能。

类型定义

// 商品相关
interface Product {
    id: string;
    name: string;
    description: string;
    price: number;
    originalPrice?: number;
    category: Category;
    images: string[];
    stock: number;
    sku: string;
    attributes: ProductAttribute[];
    rating: number;
    reviewCount: number;
    isActive: boolean;
    createdAt: Date;
    updatedAt: Date;
}

interface Category {
    id: string;
    name: string;
    slug: string;
    parent?: Category;
    children?: Category[];
}

interface ProductAttribute {
    name: string;
    value: string;
}

// 购物车相关
interface CartItem {
    productId: string;
    product: Product;
    quantity: number;
    selectedAttributes?: ProductAttribute[];
    addedAt: Date;
}

interface Cart {
    id: string;
    userId: string;
    items: CartItem[];
    subtotal: number;
    discount: number;
    tax: number;
    shipping: number;
    total: number;
    createdAt: Date;
    updatedAt: Date;
}

// 订单相关
enum OrderStatus {
    Pending = 'pending',
    Confirmed = 'confirmed',
    Processing = 'processing',
    Shipped = 'shipped',
    Delivered = 'delivered',
    Cancelled = 'cancelled',
    Refunded = 'refunded'
}

enum PaymentStatus {
    Pending = 'pending',
    Authorized = 'authorized',
    Paid = 'paid',
    Failed = 'failed',
    Refunded = 'refunded'
}

enum PaymentMethod {
    CreditCard = 'credit-card',
    DebitCard = 'debit-card',
    PayPal = 'paypal',
    Alipay = 'alipay',
    WeChatPay = 'wechat-pay',
    BankTransfer = 'bank-transfer'
}

interface Order {
    id: string;
    orderNumber: string;
    userId: string;
    items: OrderItem[];
    subtotal: number;
    discount: number;
    tax: number;
    shipping: number;
    total: number;
    status: OrderStatus;
    paymentStatus: PaymentStatus;
    paymentMethod: PaymentMethod;
    shippingAddress: Address;
    billingAddress: Address;
    notes?: string;
    createdAt: Date;
    updatedAt: Date;
    paidAt?: Date;
    shippedAt?: Date;
    deliveredAt?: Date;
}

interface OrderItem {
    productId: string;
    productName: string;
    productImage: string;
    quantity: number;
    price: number;
    subtotal: number;
    selectedAttributes?: ProductAttribute[];
}

// 优惠券
interface Coupon {
    id: string;
    code: string;
    type: 'percentage' | 'fixed';
    value: number;
    minPurchase?: number;
    maxDiscount?: number;
    expiresAt?: Date;
    usageLimit?: number;
    usageCount: number;
    isActive: boolean;
}

购物车服务实现

interface ICartService {
    getCart(userId: string): Cart;
    addItem(userId: string, productId: string, quantity: number): Cart;
    updateItemQuantity(userId: string, productId: string, quantity: number): Cart;
    removeItem(userId: string, productId: string): Cart;
    clearCart(userId: string): Cart;
    applyCoupon(userId: string, couponCode: string): Cart;
    removeCoupon(userId: string): Cart;
    calculateTotals(cart: Cart): Cart;
}

class CartService implements ICartService {
    private carts: Map<string, Cart> = new Map();
    private products: Map<string, Product> = new Map();
    private coupons: Map<string, Coupon> = new Map();
    
    getCart(userId: string): Cart {
        let cart = this.carts.get(userId);
        
        if (!cart) {
            cart = {
                id: this.generateId(),
                userId,
                items: [],
                subtotal: 0,
                discount: 0,
                tax: 0,
                shipping: 0,
                total: 0,
                createdAt: new Date(),
                updatedAt: new Date()
            };
            this.carts.set(userId, cart);
        }
        
        return cart;
    }
    
    addItem(userId: string, productId: string, quantity: number): Cart {
        const cart = this.getCart(userId);
        const product = this.products.get(productId);
        
        if (!product) {
            throw new Error('商品不存在');
        }
        
        if (!product.isActive) {
            throw new Error('商品已下架');
        }
        
        if (product.stock < quantity) {
            throw new Error(`库存不足,当前库存:${product.stock}`);
        }
        
        // 检查商品是否已在购物车中
        const existingItem = cart.items.find(item => item.productId === productId);
        
        if (existingItem) {
            // 更新数量
            const newQuantity = existingItem.quantity + quantity;
            if (product.stock < newQuantity) {
                throw new Error(`库存不足,当前库存:${product.stock}`);
            }
            existingItem.quantity = newQuantity;
        } else {
            // 添加新商品
            const cartItem: CartItem = {
                productId,
                product,
                quantity,
                addedAt: new Date()
            };
            cart.items.push(cartItem);
        }
        
        cart.updatedAt = new Date();
        return this.calculateTotals(cart);
    }
    
    updateItemQuantity(userId: string, productId: string, quantity: number): Cart {
        const cart = this.getCart(userId);
        const item = cart.items.find(item => item.productId === productId);
        
        if (!item) {
            throw new Error('购物车中没有该商品');
        }
        
        if (quantity <= 0) {
            return this.removeItem(userId, productId);
        }
        
        if (item.product.stock < quantity) {
            throw new Error(`库存不足,当前库存:${item.product.stock}`);
        }
        
        item.quantity = quantity;
        cart.updatedAt = new Date();
        
        return this.calculateTotals(cart);
    }
    
    removeItem(userId: string, productId: string): Cart {
        const cart = this.getCart(userId);
        const index = cart.items.findIndex(item => item.productId === productId);
        
        if (index > -1) {
            cart.items.splice(index, 1);
            cart.updatedAt = new Date();
        }
        
        return this.calculateTotals(cart);
    }
    
    clearCart(userId: string): Cart {
        const cart = this.getCart(userId);
        cart.items = [];
        cart.updatedAt = new Date();
        
        return this.calculateTotals(cart);
    }
    
    applyCoupon(userId: string, couponCode: string): Cart {
        const cart = this.getCart(userId);
        const coupon = Array.from(this.coupons.values()).find(
            c => c.code === couponCode && c.isActive
        );
        
        if (!coupon) {
            throw new Error('优惠券无效');
        }
        
        if (coupon.expiresAt && coupon.expiresAt < new Date()) {
            throw new Error('优惠券已过期');
        }
        
        if (coupon.usageLimit && coupon.usageCount >= coupon.usageLimit) {
            throw new Error('优惠券已达到使用次数上限');
        }
        
        if (coupon.minPurchase && cart.subtotal < coupon.minPurchase) {
            throw new Error(`最低消费金额为 ${coupon.minPurchase} 元`);
        }
        
        // 计算折扣
        let discount = 0;
        if (coupon.type === 'percentage') {
            discount = cart.subtotal * (coupon.value / 100);
        } else {
            discount = coupon.value;
        }
        
        if (coupon.maxDiscount && discount > coupon.maxDiscount) {
            discount = coupon.maxDiscount;
        }
        
        cart.discount = discount;
        cart.updatedAt = new Date();
        
        return this.calculateTotals(cart);
    }
    
    removeCoupon(userId: string): Cart {
        const cart = this.getCart(userId);
        cart.discount = 0;
        cart.updatedAt = new Date();
        
        return this.calculateTotals(cart);
    }
    
    calculateTotals(cart: Cart): Cart {
        // 计算小计
        cart.subtotal = cart.items.reduce((sum, item) => {
            return sum + (item.product.price * item.quantity);
        }, 0);
        
        // 计算税费(假设税率为 10%)
        cart.tax = (cart.subtotal - cart.discount) * 0.1;
        
        // 计算运费(假设满 100 免运费)
        cart.shipping = cart.subtotal >= 100 ? 0 : 10;
        
        // 计算总价
        cart.total = cart.subtotal - cart.discount + cart.tax + cart.shipping;
        
        return cart;
    }
    
    private generateId(): string {
        return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }
}

订单服务实现

interface IOrderService {
    createOrder(userId: string, shippingAddress: Address, paymentMethod: PaymentMethod): Order;
    getOrder(orderId: string): Order | undefined;
    getUserOrders(userId: string): Order[];
    updateOrderStatus(orderId: string, status: OrderStatus): Order;
    cancelOrder(orderId: string): Order;
    processPayment(orderId: string, paymentDetails: any): Order;
    refundOrder(orderId: string): Order;
}

class OrderService implements IOrderService {
    private orders: Map<string, Order> = new Map();
    
    constructor(private cartService: CartService) {}
    
    createOrder(
        userId: string,
        shippingAddress: Address,
        paymentMethod: PaymentMethod
    ): Order {
        const cart = this.cartService.getCart(userId);
        
        if (cart.items.length === 0) {
            throw new Error('购物车为空');
        }
        
        // 验证库存
        for (const item of cart.items) {
            if (item.product.stock < item.quantity) {
                throw new Error(`商品 ${item.product.name} 库存不足`);
            }
        }
        
        // 创建订单项
        const orderItems: OrderItem[] = cart.items.map(item => ({
            productId: item.productId,
            productName: item.product.name,
            productImage: item.product.images[0],
            quantity: item.quantity,
            price: item.product.price,
            subtotal: item.product.price * item.quantity,
            selectedAttributes: item.selectedAttributes
        }));
        
        // 生成订单号
        const orderNumber = this.generateOrderNumber();
        
        // 创建订单
        const order: Order = {
            id: this.generateId(),
            orderNumber,
            userId,
            items: orderItems,
            subtotal: cart.subtotal,
            discount: cart.discount,
            tax: cart.tax,
            shipping: cart.shipping,
            total: cart.total,
            status: OrderStatus.Pending,
            paymentStatus: PaymentStatus.Pending,
            paymentMethod,
            shippingAddress,
            billingAddress: shippingAddress, // 简化处理,使用相同地址
            createdAt: new Date(),
            updatedAt: new Date()
        };
        
        this.orders.set(order.id, order);
        
        // 清空购物车
        this.cartService.clearCart(userId);
        
        // 更新库存
        for (const item of cart.items) {
            item.product.stock -= item.quantity;
        }
        
        return order;
    }
    
    getOrder(orderId: string): Order | undefined {
        return this.orders.get(orderId);
    }
    
    getUserOrders(userId: string): Order[] {
        return Array.from(this.orders.values())
            .filter(order => order.userId === userId)
            .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
    }
    
    updateOrderStatus(orderId: string, status: OrderStatus): Order {
        const order = this.orders.get(orderId);
        if (!order) {
            throw new Error('订单不存在');
        }
        
        order.status = status;
        order.updatedAt = new Date();
        
        // 更新特定状态的时间戳
        if (status === OrderStatus.Shipped) {
            order.shippedAt = new Date();
        } else if (status === OrderStatus.Delivered) {
            order.deliveredAt = new Date();
        }
        
        return order;
    }
    
    cancelOrder(orderId: string): Order {
        const order = this.orders.get(orderId);
        if (!order) {
            throw new Error('订单不存在');
        }
        
        // 只有待处理和已确认的订单可以取消
        if (![OrderStatus.Pending, OrderStatus.Confirmed].includes(order.status)) {
            throw new Error('当前订单状态不允许取消');
        }
        
        order.status = OrderStatus.Cancelled;
        order.updatedAt = new Date();
        
        // 恢复库存
        // 实际应用中需要从产品服务获取产品并更新库存
        
        return order;
    }
    
    processPayment(orderId: string, paymentDetails: any): Order {
        const order = this.orders.get(orderId);
        if (!order) {
            throw new Error('订单不存在');
        }
        
        if (order.paymentStatus !== PaymentStatus.Pending) {
            throw new Error('订单已支付或支付失败');
        }
        
        try {
            // 实际应用中这里会调用支付网关 API
            // 模拟支付成功
            order.paymentStatus = PaymentStatus.Paid;
            order.paidAt = new Date();
            order.status = OrderStatus.Confirmed;
            order.updatedAt = new Date();
            
            return order;
        } catch (error) {
            order.paymentStatus = PaymentStatus.Failed;
            order.updatedAt = new Date();
            throw new Error('支付失败');
        }
    }
    
    refundOrder(orderId: string): Order {
        const order = this.orders.get(orderId);
        if (!order) {
            throw new Error('订单不存在');
        }
        
        if (order.paymentStatus !== PaymentStatus.Paid) {
            throw new Error('订单未支付,无法退款');
        }
        
        if (order.status === OrderStatus.Delivered) {
            // 可以添加退款申请审核流程
        }
        
        order.paymentStatus = PaymentStatus.Refunded;
        order.status = OrderStatus.Refunded;
        order.updatedAt = new Date();
        
        // 恢复库存
        // 实际应用中需要从产品服务获取产品并更新库存
        
        return order;
    }
    
    private generateId(): string {
        return `order_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }
    
    private generateOrderNumber(): string {
        const date = new Date();
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        const random = Math.random().toString(36).substr(2, 6).toUpperCase();
        
        return `${year}${month}${day}${random}`;
    }
}

使用示例

// 创建服务实例
const cartService = new CartService();
const orderService = new OrderService(cartService);

// 添加商品到购物车
const userId = 'user123';
cartService.addItem(userId, 'product1', 2);
cartService.addItem(userId, 'product2', 1);

// 查看购物车
const cart = cartService.getCart(userId);
console.log('购物车:', cart);

// 应用优惠券
cartService.applyCoupon(userId, 'SAVE10');

// 创建订单
const shippingAddress: Address = {
    street: '长安街1号',
    city: '北京',
    state: '北京市',
    zipCode: '100000',
    country: '中国'
};

const order = orderService.createOrder(
    userId,
    shippingAddress,
    PaymentMethod.Alipay
);

console.log('订单创建成功:', order.orderNumber);

// 处理支付
const paidOrder = orderService.processPayment(order.id, {
    // 支付详情
});

console.log('支付成功:', paidOrder);

// 查询用户订单
const userOrders = orderService.getUserOrders(userId);
console.log('用户订单:', userOrders);

总结

通过这些综合实战项目,您可以学习到:

1. Todo 应用

  • 基础的 CRUD 操作
  • 枚举类型的使用
  • 数据过滤和查询
  • 统计功能实现

2. 用户管理系统

  • 用户认证和授权
  • 角色和权限管理
  • 会话管理
  • 密码加密和验证

3. 电商购物车

  • 购物车状态管理
  • 订单处理流程
  • 支付集成
  • 库存管理

关键学习点

  1. 类型安全:利用 TypeScript 的类型系统确保代码安全
  2. 接口设计:定义清晰的服务接口
  3. 错误处理:完善的错误检查和异常处理
  4. 业务逻辑:复杂业务场景的实现
  5. 数据验证:输入验证和状态检查
  6. 代码组织:合理的代码结构和模块划分

实践建议

  1. 逐步实现:从简单功能开始,逐步增加复杂度
  2. 测试驱动:为关键功能编写单元测试
  3. 重构优化:不断改进代码质量
  4. 实际应用:将这些模式应用到真实项目中
  5. 扩展功能:根据需求添加更多功能

这些项目涵盖了大多数实际应用中常见的场景,掌握这些模式将帮助您更好地使用 TypeScript 开发复杂的应用程序。