TypeScript 一日速通指南:以订单管理系统实战为核心

一、环境搭建(30分钟)

1.1 基础环境配置

bash 复制代码
# 安装Node.js(需v14+版本)
node -v # 验证安装
npm install -g typescript # 全局安装编译器
tsc --version # 确认版本≥4.0

1.2 项目初始化

bash 复制代码
mkdir order-ts-demo && cd order-ts-demo
npm init -y
tsc --init # 生成tsconfig.json

关键配置项

json 复制代码
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist",
    "baseUrl": "./src",
    "paths": {
      "@models/*": ["models/*"],
      "@services/*": ["services/*"]
    }
  },
  "include": ["src/**/*"]
}

二、类型系统精要(120分钟)

2.1 基础类型体系(30分钟)

typescript 复制代码
// 原始类型
const orderId: string = "ORD-20260314";
const amount: number = 99.99;
const status: "pending" | "paid" | "shipped" = "pending";

// 特殊类型
let anyData: any = apiResponse; // 谨慎使用
let unknownData: unknown = userInput; // 安全类型

// 复合类型
type OrderItem = {
  productId: string;
  quantity: number;
  price: number;
};

// 枚举类型
enum OrderStatus {
  PENDING = "pending",
  PAID = "paid",
  SHIPPED = "shipped"
}

2.2 高级类型模式(45分钟)

typescript 复制代码
// 联合类型与类型守卫
type PaymentMethod = "credit" | "paypal" | "wechat";
function isCreditCard(method: PaymentMethod): method is "credit" {
  return method === "credit";
}

// 泛型约束
interface Repository<T extends { id: string }> {
  findById(id: string): T | null;
  save(entity: T): void;
}

// 映射类型实战
type ReadonlyOrder = Readonly<Order>;
type PartialOrder = Partial<Order>;

// 条件类型应用
type IsPaid<T> = T extends { status: "paid" } ? true : false;

2.3 类型系统深度(45分钟)

typescript 复制代码
// 类型别名与接口
type User = {
  id: string;
  name: string;
  email: string;
  roles: ("admin" | "user")[];
};

interface OrderService {
  createOrder(user: User, items: OrderItem[]): Promise<Order>;
}

// 类型断言与推断
const parseResponse = (res: unknown): Order => {
  if (typeof res !== "object") throw new Error();
  return res as Order;
};

// 索引类型与键操作
type OrderKeys = keyof Order; // "id" | "userId" | ...

三、订单管理系统实战(180分钟)

3.1 数据模型设计(40分钟)

typescript 复制代码
// src/models/order.ts
export enum OrderStatus {
  PENDING = "pending",
  PAID = "paid",
  SHIPPED = "shipped",
  CANCELLED = "cancelled"
}

export interface OrderItem {
  productId: string;
  quantity: number;
  unitPrice: number;
  discount?: number; // 新增可选字段
}

export class Order {
  constructor(
    public readonly id: string,
    public readonly userId: string,
    private _items: OrderItem[],
    private _status: OrderStatus = OrderStatus.PENDING
  ) {
    this._validate();
  }

  private _validate() {
    if (this._items.some(item => item.quantity <= 0)) {
      throw new Error("商品数量必须大于0");
    }
  }

  get totalAmount(): number {
    return this._items.reduce(
      (sum, item) => sum + item.quantity * item.unitPrice * (1 - (item.discount || 0)),
      0
    );
  }

  updateStatus(newStatus: OrderStatus) {
    if (!Object.values(OrderStatus).includes(newStatus)) {
      throw new Error("无效的订单状态");
    }
    this._status = newStatus;
  }
}

3.2 服务层实现(60分钟)

typescript 复制代码
// src/services/orderService.ts
import { Order, OrderStatus } from "../models/order";

class OrderService implements Repository<Order> {
  private orders: Order[] = [];

  createOrder(userId: string, items: OrderItem[]): Order {
    const newOrder = new Order(
      `ORD-${Date.now()}`,
      userId,
      items
    );
    this.orders.push(newOrder);
    return newOrder;
  }

  findById(id: string): Order | null {
    return this.orders.find(order => order.id === id) || null;
  }

  cancelOrder(id: string) {
    const order = this.findById(id);
    if (order) {
      if (order.status === OrderStatus.PAID) {
        throw new Error("已支付订单不可取消");
      }
      order.updateStatus(OrderStatus.CANCELLED);
    }
  }
}

3.3 类型安全校验(80分钟)

typescript 复制代码
// src/utils/validators.ts
import { OrderItem } from "../models/order";

export const validateOrderItem = (item: unknown): item is OrderItem => {
  return (
    typeof item === "object" &&
    "productId" in item &&
    typeof item.productId === "string" &&
    "quantity" in item &&
    Number.isInteger(item.quantity) &&
    item.quantity > 0 &&
    "unitPrice" in item &&
    typeof item.unitPrice === "number"
  );
};

// 使用示例
const processOrder = (items: unknown[]) => {
  if (!Array.isArray(items)) throw new Error("订单项必须为数组");
  const validatedItems = items.filter(validateOrderItem);
  if (validatedItems.length === 0) throw new Error("无有效订单项");
};

四、进阶特性实战(120分钟)

4.1 泛型约束(30分钟)

typescript 复制代码
// src/repositories/baseRepository.ts
export interface IRepository<T extends { id: string }> {
  findById(id: string): T | null;
  save(entity: T): void;
  delete(id: string): void;
}

// 实现类
class OrderRepository implements IRepository<Order> {
  private storage: Order[] = [];
  
  save(entity: Order) {
    const existing = this.findById(entity.id);
    if (existing) throw new Error("订单已存在");
    this.storage.push(entity);
  }
}

4.2 映射类型(30分钟)

typescript 复制代码
// src/types/orderTypes.ts
type PartialOrder = Partial<Order>;
type ReadonlyOrder = Readonly<Order>;

// 高级映射
type OrderWithoutSensitive = Omit<Order, "userId">;
type OrderPreview = Pick<Order, "id" | "totalAmount" | "status">;

4.3 条件类型(30分钟)

typescript 复制代码
// src/types/statusCheck.ts
type IsPaid<T> = T extends { status: "paid" } ? T : never;

// 使用示例
const getPaidOrders = (orders: Order[]): IsPaid<Order>[] => {
  return orders.filter(order => order.status === "paid") as IsPaid<Order>[];
};

4.4 装饰器应用(30分钟)

typescript 复制代码
// src/decorators/logging.ts
function LogMethod(target: any, name: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`调用方法: ${name},参数: ${JSON.stringify(args)}`);
    return original.apply(this, args);
  };
}

// 使用示例
class PaymentService {
  @LogMethod
  processPayment(order: Order) {
    // 支付逻辑
  }
}

五、工程化配置(90分钟)

5.1 tsconfig.json 优化(30分钟)

json 复制代码
{
  "compilerOptions": {
    "strictNullChecks": true,
    "noImplicitAny": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "forceConsistentCasingInFileNames": true,
    "paths": {
      "@/*": ["src/*"]
    },
    "plugins": [
      { "name": "typescript-eslint" }
    ]
  }
}

5.2 调试配置(30分钟)

json 复制代码
// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug TypeScript",
      "preLaunchTask": "tsc: build - tsconfig.json",
      "program": "${workspaceFolder}/dist/index.js",
      "outFiles": ["${workspaceFolder}/dist/**/*.js"],
      "sourceMaps": true
    }
  ]
}

5.3 构建集成(30分钟)

json 复制代码
// package.json
{
  "scripts": {
    "build": "tsc && eslint src --fix",
    "start": "ts-node src/index.ts",
    "test": "jest --coverage"
  },
  "devDependencies": {
    "@types/jest": "^29.0.0",
    "ts-jest": "^29.0.0",
    "typescript-eslint": "^6.0.0"
  }
}

六、最佳实践与避坑(90分钟)

6.1 类型设计原则(30分钟)

  1. 单一职责原则 :每个类型只描述一个概念

    typescript 复制代码
    // 不推荐
    type UserWithOrder = User & { orders: Order[] };
    
    // 推荐
    interface User {
      orders: Order[];
    }
  2. 开闭原则 :通过泛型扩展而非修改基类

    typescript 复制代码
    class BaseRepository<T> {
      // 基础方法
    }
    
    class OrderRepository extends BaseRepository<Order> {
      // 扩展方法
    }

6.2 常见陷阱(30分钟)

问题类型 示例代码 修复方案 来源
any滥用 let data: any = apiData; 改用unknown+类型收窄
类型断言误用 (res as Order).id 增加类型守卫
泛型约束缺失 function getId<T>(item: T): string 添加T extends {id: string}

6.3 性能优化(30分钟)

  1. 编译优化

    json 复制代码
    // tsconfig.json
    {
      "compilerOptions": {
        "incremental": true,
        "skipLibCheck": true,
        "composite": true
      }
    }
  2. 代码优化

    typescript 复制代码
    // 避免过度使用any
    type ApiResponse<T> = {
      data: T;
      status: number;
    };
    
    // 使用工具类型
    type PartialWithRequired<T, K extends keyof T> = Partial<T> & Pick<T, K>;

七、扩展学习资源

  1. 类型安全库

    • Zod:运行时类型校验
    • io-ts:函数式类型验证
    typescript 复制代码
    import { z } from 'zod';
    
    const OrderSchema = z.object({
      id: z.string().uuid(),
      items: z.array(
        z.object({
          productId: z.string(),
          quantity: z.number().min(1)
        })
      )
    });
  2. 可视化工具

    • TypeScript Playground
    • CodeSandbox实时预览

https://www.typescriptlang.org/

TypeScript 优缺点精要总结

核心优势
  1. 静态类型系统
    • 编译时类型检查,提前捕获类型错误(如参数类型不匹配、属性缺失等),减少运行时异常
    • 增强代码可读性和可维护性,类型注解本身就是文档
    • 支持类型推断,减少冗余代码(如 let num = 10 自动推断为 number
  2. 强大的工具链支持
    • IDE 智能补全、重构、跳转定义等功能显著提升开发效率(如 VS Code 深度集成)
    • 结合 ESLint、Prettier 等工具实现代码规范自动化
  3. 工程化优势
    • 渐进式采用:可逐步迁移 JavaScript 项目,支持混合开发
    • 严格模式(strict: true)强制规范代码,避免潜在隐患
    • 泛型、接口、枚举等特性支持复杂业务建模
  4. 生态完善
    • 社区提供 DefinitelyTyped 类型定义库(@types),覆盖主流第三方库
    • 与 React、Vue、Angular 等框架深度集成,提供类型安全的组件开发体验

主要局限
  1. 运行时类型安全缺失
    • 编译后类型信息丢失,仍需手动添加运行时校验(如 API 数据校验)
    • any 和非空断言(!)可能绕过类型检查,引入风险
  2. 学习与开发成本
    • 需掌握接口、泛型、类型守卫等概念,对新手不友好
    • 类型定义复杂场景(如递归类型、条件类型)编写难度高
  3. 构建性能影响
    • 大型项目中类型检查可能拖慢编译速度,需依赖增量编译或 Babel 转译优化
  4. 生态兼容性问题
    • 部分老旧库缺乏类型定义,需手动维护 .d.ts 文件
    • 非标准 JavaScript 语法(如装饰器)需额外配置

适用场景建议
推荐使用 谨慎使用
大型团队协作项目 快速原型开发/小型脚本
长期维护的核心业务系统 对构建速度敏感的项目
需要严格代码规范的中后台系统 依赖非类型友好库的轻量级应用

关键决策参考
  • 优势优先级:类型安全 > 工具支持 > 生态兼容性
  • 风险规避 :避免滥用 any,优先启用严格模式,结合运行时校验库(如 Zod)
  • 学习路径:从基础类型入手,逐步掌握泛型、高级类型和工具链配置

总结:TypeScript 是提升代码质量的利器,但需权衡团队能力与项目规模。对于追求长期可维护性的项目,其价值远超初期学习成本。


相关推荐
yqzyy1 小时前
Nginx 配置:alias 和 root 的区别
前端·javascript·nginx
冰糖雪梨dd1 小时前
【JavaScript】 substring()方法详解
开发语言·前端·javascript
John Song2 小时前
npm查看全局安装了哪些命令
前端·npm·node.js
无心水2 小时前
【文档解析】4、跨平台文档解析:JS/Go/C#全攻略
javascript·后端·golang·c#·架构师·大数据分析·分布式系统利器
清汤饺子2 小时前
用了大半年 Claude Code,我总结了 16 个实用技巧
前端·javascript·后端
兆子龙3 小时前
ahooks useMemoizedFn:解决 useCallback 的依赖地狱
java·javascript
兆子龙3 小时前
MyBatis-Plus 踩坑血泪史:我们踩过的那些坑
typescript
mCell9 小时前
【短文】不是最强,是最适合
前端·aigc·deepseek
余瑜鱼鱼鱼10 小时前
HTML常用标签总结
前端·html