模块和命名空间 
简介 
模块提供了一种封装代码的方式,而命名空间则是一种在全局作用域内组织代码的方法。
模块 
模块是 TypeScript 中组织和封装代码的主要方式。每个文件可以被视为一个模块,可以导出和导入变量、函数、类等。
模块的导出 
有多种方式可以导出模块内容:
typescript
// 命名导出
export const PI = 3.14159
export function calculateCircumference(radius: number): number {
  return 2 * PI * radius
}
// 默认导出
export default class Circle {
  constructor(public radius: number) {}
  area(): number {
    return PI * this.radius ** 2
  }
}
// 重命名导出
const _internalPI = 3.14159
export { _internalPI as PI }模块的导入 
相应地,有多种方式可以导入模块内容:
typescript
// 导入命名导出
import { PI, calculateCircumference } from './math'
// 导入默认导出
import Circle from './circle'
// 导入全部并重命名
import * as MathUtils from './math'
// 重命名导入
import { PI as CirclePI } from './math'命名空间 
命名空间是 TypeScript 特有的特性,用于在全局作用域内组织代码,避免命名冲突。
typescript
namespace Geometry {
  export interface Point {
    x: number
    y: number
  }
  export class Line {
    constructor(public start: Point, public end: Point) {}
    length(): number {
      const dx = this.end.x - this.start.x
      const dy = this.end.y - this.start.y
      return Math.sqrt(dx * dx + dy * dy)
    }
  }
}
// 使用命名空间
let point: Geometry.Point = { x: 0, y: 0 }
let line = new Geometry.Line(point, { x: 3, y: 4 })
console.log(line.length()) // 输出: 5命名空间可以通过以下方式引入和使用: 
- 在同一文件中使用: 直接使用命名空间名称加上点号访问其中的成员。 typescript- namespace Geometry { export interface Point { x: number; y: number; } } let point: Geometry.Point = { x: 0, y: 0 };
- 跨文件使用: a. 在定义命名空间的文件中,使用 - namespace关键字定义命名空间。 b. 在使用的文件中,使用- /// <reference path="..." />指令引入命名空间文件。- // geometry.ts typescript- namespace Geometry { export interface Point { x: number; y: number; } }- // main.ts typescript- /// <reference path="geometry.ts" /> let point: Geometry.Point = { x: 0, y: 0 };
- 使用 - import别名: 可以使用- import给命名空间创建一个别名,简化使用。typescript- namespace Shapes { export namespace Polygons { export class Triangle { /* ... */ } export class Square { /* ... */ } } } import polygons = Shapes.Polygons; let sq = new polygons.Square(); // 等同于 new Shapes.Polygons.Square()
模块解析策略 
模块解析是指编译器如何确定导入的内容指向哪个文件。TypeScript 有两种解析策略:Classic 和 Node。
1. Classic 策略 
这是 TypeScript 最初的默认策略,主要用于向后兼容。
- 相对导入(以 /、./或../开头):从导入文件所在目录开始查找。
- 非相对导入:从包含导入文件的目录开始,逐级向上级目录查找。
例如,对于 import { a } from "moduleA":
- /root/src/moduleA.ts
- /root/src/moduleA.d.ts
- /root/moduleA.ts
- /root/moduleA.d.ts
- /moduleA.ts
- /moduleA.d.ts
2. Node 策略 
这种策略模仿 Node.js 的模块解析机制,是现在推荐使用的策略。
- 相对导入:与 Classic 策略类似。
- 非相对导入: - 查找 package.json文件中的"types"字段。
- 查找 index.d.ts文件。
- 查找 package.json文件中的"main"字段指定的文件。
- 查找 index.js文件。
 
- 查找 
例如,对于 import { a } from "moduleA",假设当前文件在 /root/src/module.ts:
- /root/src/node_modules/moduleA.ts
- /root/src/node_modules/moduleA.tsx
- /root/src/node_modules/moduleA.d.ts
- /root/src/node_modules/moduleA/package.json(如果指定了- "types"属性)
- /root/src/node_modules/moduleA/index.ts
- /root/src/node_modules/moduleA/index.tsx
- /root/src/node_modules/moduleA/index.d.ts
- 然后在上级目录 /root/node_modules中重复步骤 1-7
- 再在 /node_modules中重复步骤 1-7
配置模块解析策略 
在 tsconfig.json 中可以配置模块解析策略:
json
{
  "compilerOptions": {
    "moduleResolution": "node",  // 或 "classic"
    "baseUrl": "./",  // 基本目录,用于解析非相对模块名
    "paths": {  // 路径映射,用于模块名到相对于 baseUrl 的路径映射
      "jquery": ["node_modules/jquery/dist/jquery"]
    }
  }
}