<返回目录     Powered by claud/xia兄

第10课: 模块系统

什么是模块?

模块是TypeScript中组织代码的方式。每个文件都是一个模块,模块可以导出和导入功能,实现代码的封装和重用。

导出 (Export)

// math.ts
export const pi = 3.14;

export function add(x: number, y: number): number {
  return x + y;
}

export class Calculator {
  multiply(x: number, y: number): number {
    return x * y;
  }
}

// 导出接口
export interface User {
  name: string;
  age: number;
}

// 导出类型别名
export type ID = string | number;

默认导出 (Default Export)

// calculator.ts
export default class Calculator {
  add(x: number, y: number): number {
    return x + y;
  }
}

// 或者
class Calculator {
  add(x: number, y: number): number {
    return x + y;
  }
}
export default Calculator;

导入 (Import)

// 导入命名导出
import { pi, add, Calculator } from "./math";

// 导入并重命名
import { add as sum } from "./math";

// 导入所有
import * as math from "./math";
console.log(math.pi);
console.log(math.add(1, 2));

// 导入默认导出
import Calculator from "./calculator";

// 混合导入
import Calculator, { pi, add } from "./math";

重新导出 (Re-export)

// utils/index.ts
export { add, subtract } from "./math";
export { formatDate } from "./date";
export * from "./string";

// 重新导出并重命名
export { add as sum } from "./math";

// 重新导出默认导出
export { default as Calculator } from "./calculator";

动态导入

// 动态导入返回Promise
async function loadModule() {
  const math = await import("./math");
  console.log(math.add(1, 2));
}

// 条件导入
if (condition) {
  import("./heavy-module").then(module => {
    module.doSomething();
  });
}

命名空间 (Namespace)

命名空间是TypeScript特有的组织代码方式(不推荐在现代项目中使用):

namespace Validation {
  export interface StringValidator {
    isValid(s: string): boolean;
  }

  export class LettersOnlyValidator implements StringValidator {
    isValid(s: string): boolean {
      return /^[A-Za-z]+$/.test(s);
    }
  }
}

let validator = new Validation.LettersOnlyValidator();

模块解析策略

// tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "node", // 或 "classic"
    "baseUrl": "./src",
    "paths": {
      "@utils/*": ["utils/*"],
      "@components/*": ["components/*"]
    }
  }
}

// 使用路径映射
import { add } from "@utils/math";
import Button from "@components/Button";

模块格式

// tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",  // Node.js
    // "module": "es2015",  // ES6模块
    // "module": "amd",     // AMD
    // "module": "umd",     // UMD
    // "module": "esnext"   // 最新ES模块
  }
}

CommonJS vs ES模块

// CommonJS (Node.js)
const math = require("./math");
module.exports = { add, subtract };

// ES模块
import * as math from "./math";
export { add, subtract };

// TypeScript可以导入CommonJS模块
import express = require("express");

类型导入导出

// 仅导入类型
import type { User } from "./types";

// 导出类型
export type { User, Product };

// 混合导入
import { type User, createUser } from "./user";

模块增强

// 扩展现有模块
declare module "./observable" {
  interface Observable {
    map(f: (x: T) => U): Observable;
  }
}

// 全局模块增强
declare global {
  interface Array {
    toObservable(): Observable;
  }
}

实际应用示例

// types.ts
export interface User {
  id: number;
  name: string;
  email: string;
}

// api.ts
import type { User } from "./types";

export async function fetchUser(id: number): Promise {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}

// index.ts
import { fetchUser } from "./api";
import type { User } from "./types";

async function main() {
  const user: User = await fetchUser(1);
  console.log(user.name);
}

main();
模块最佳实践:
  • 每个文件只导出一个主要功能(单一职责)
  • 使用命名导出而不是默认导出(更好的重构支持)
  • 使用路径映射简化导入路径
  • 使用type导入仅导入类型,减少运行时开销
练习:
  1. 创建一个模块,导出多个工具函数
  2. 使用默认导出和命名导出
  3. 配置路径映射,简化导入路径
  4. 使用动态导入实现按需加载