Skip to content

理解命名空间、模块、声明文件

命名空间(Namespace)

命名空间是 TypeScript 提供的一种组织代码的方式,用于避免全局作用域中的命名冲突。它可以将相关的代码组织在一起,形成一个独立的作用域。

基本语法

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

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

  // 未导出的内容在命名空间外部无法访问
  const defaultLength = 5;
}

嵌套命名空间

typescript
namespace Shapes {
  export namespace Polygons {
    export class Triangle {}
    export class Square {}
  }
}

// 使用
let sq = new Shapes.Polygons.Square();

别名

typescript
import polygons = Shapes.Polygons;
let sq = new polygons.Square();

模块(Module)

模块是 TypeScript/ES6 中更现代的代码组织方式,每个文件就是一个模块。

导出方式

typescript
// 单个导出
export interface StringValidator {
  isAcceptable(s: string): boolean;
}

// 默认导出
export default class DefaultValidator {
  // ...
}

// 批量导出
const validator1 = {
  /* ... */
};
const validator2 = {
  /* ... */
};
export { validator1, validator2 };

// 重命名导出
export { validator1 as mainValidator };

导入方式

typescript
// 基本导入
import { StringValidator } from './validators';

// 默认导入
import DefaultValidator from './validators';

// 全部导入
import * as validators from './validators';

// 重命名导入
import { mainValidator as validator } from './validators';

声明文件(.d.ts)

声明文件用于为 JavaScript 库提供类型信息,通常以 .d.ts 为扩展名。

全局声明

typescript
// global.d.ts
declare global {
  interface Window {
    customProperty: string;
  }
}

// 声明全局变量
declare const VERSION: string;

// 声明全局函数
declare function getData(id: number): Promise<any>;

// 声明全局类
declare class MyGlobalClass {
  constructor(options: MyGlobalClass.Options);
  method(): void;
}

模块声明

typescript
// lodash.d.ts
declare module 'lodash' {
  export function chunk<T>(array: T[], size?: number): T[][];
  export function debounce(
    func: Function,
    wait?: number,
    options?: DebounceOptions
  ): Function;
}

命名空间声明

typescript
// jquery.d.ts
declare namespace $ {
  function ajax(url: string, settings?: any): void;

  interface JQueryStatic {
    get(url: string): Promise<any>;
    post(url: string, data: any): Promise<any>;
  }
}

三斜线指令(Triple-Slash Directives)

三斜线指令是包含单个 XML 标签的单行注释。它们只能出现在文件的顶部,并且仅在声明文件中使用。

1. 引用路径 (path)

typescript
/// <reference path="./other-file.d.ts" />

作用:

  • 声明文件间的依赖关系
  • 指定编译时需要包含的文件
  • 多个声明文件合并

使用场景:

typescript
// shapes.d.ts
interface Shape {
  color: string;
}

// circle.d.ts
/// <reference path="shapes.d.ts" />
interface Circle extends Shape {
  radius: number;
}

2. 引用类型 (types)

typescript
/// <reference types="node" />

作用:

  • 声明对 @types 包的依赖
  • 引入第三方库的类型定义
  • 用于声明文件而不是源文件

使用场景:

typescript
/// <reference types="jquery" />
declare function $(selector: string): JQuery;

3. 引用库 (lib)

typescript
/// <reference lib="es2015" />

作用:

  • 引入内置库的类型定义
  • 类似于 tsconfig.json 中的 lib 选项
  • 在特定文件中启用特定的库

4. 引用 no-default-lib

typescript
/// <reference no-default-lib="true" />

作用:

  • 标记文件为默认库
  • 告诉编译器不要包含默认库(如 lib.d.ts)
  • 通常用于自定义运行时环境

5. amd-module

typescript
/// <amd-module name="nameOfModule" />

作用:

  • 给生成的 AMD 模块命名
  • 用于 AMD 模块系统的兼容性

使用注意事项

  1. 位置要求
typescript
// 正确
/// <reference path="..." />
import { something } from './module';

// 错误
import { something } from './module';
/// <reference path="..." /> // 不能在其他语句后面
  1. 优先级
typescript
// tsconfig.json 中的配置优先级高于三斜线指令
{
    "compilerOptions": {
        "types": ["node", "jest"]
    }
}
  1. 模块解析
typescript
// 相对路径
/// <reference path="./types.d.ts" />

// 包引用
/// <reference types="node" />

最佳实践

  1. 现代项目建议
typescript
// 推荐使用 package.json 和 tsconfig.json 管理依赖
{
    "dependencies": {
        "@types/node": "^14.14.31"
    }
}
  1. 声明文件组织
typescript
// index.d.ts
/// <reference path="./interfaces.d.ts" />
/// <reference path="./types.d.ts" />
/// <reference path="./constants.d.ts" />

export * from './interfaces';
export * from './types';
  1. 避免过度使用
typescript
// 不推荐
/// <reference path="./file1.d.ts" />
/// <reference path="./file2.d.ts" />
/// <reference path="./file3.d.ts" />

// 推荐使用模块导入
import { Type1 } from './file1';
import { Type2 } from './file2';

常见问题解决

  1. 路径解析问题
typescript
// 使用相对路径
/// <reference path="../typings/jquery.d.ts" />

// 使用绝对路径
/// <reference path="/user/typescript/typings/jquery.d.ts" />
  1. 类型冲突
typescript
// 通过命名空间解决
/// <reference path="lib1.d.ts" />
/// <reference path="lib2.d.ts" />

declare namespace MyLib {
  // 避免冲突的类型定义
}
  1. 循环依赖
typescript
// a.d.ts
/// <reference path="b.d.ts" />
interface A {
  b: B;
}

// b.d.ts
/// <reference path="a.d.ts" /> // 避免这种循环引用
interface B {
  a: A;
}

总结

命名空间使用建议

  1. 避免在现代应用中过度使用命名空间
  2. 适用于组织大型应用中的工具函数或内部模块
  3. 命名空间嵌套不要超过两层
  4. 使用 export 谨慎导出必要的内容

模块使用建议

  1. 一个文件一个模块,保持职责单一
  2. 使用明确的导入导出语句
  3. 避免使用 export default
  4. 合理使用路径别名简化导入路径

声明文件编写建议

  1. 为所有公共 API 提供完整的类型信息
  2. 使用 JSDoc 注释提供详细文档
  3. 遵循 DefinitelyTyped 的规范
  4. 使用 declare 关键字声明全局内容