Skip to content

TypeScript 命名空间

随着应用程序变得越来越复杂,全局作用域中的变量和函数数量会急剧增加,这很容易导致命名冲突。命名空间(Namespace)是 TypeScript 早期版本中用来解决这个问题的一种方式。它允许你将相关的代码组织在一个逻辑分组中,避免污染全局作用域。

注意:在现代 TypeScript 开发中,推荐使用 模块(Modules)(即 ES6 的 import/export)来组织代码,而不是命名空间。模块提供了更好的代码隔离和依赖管理。然而,理解命名空间仍然很重要,因为在一些旧的代码库或特定的场景(如编写全局库的声明文件)中仍然会遇到它。

什么是命名空间?

命名空间提供了一种将代码封装在特定作用域内的方法。你可以使用 namespace 关键字来定义一个命名空间。

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

    const lettersRegexp = /^[A-Za-z]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}

在这个例子中,我们将验证相关的接口和类都放在了 Validation 命名空间中。

  • 默认情况下,命名空间中的所有内容都是私有的。
  • 你必须使用 export 关键字来使命名空间中的成员(如接口、类、变量、函数)在外部可见。

使用命名空间

要使用命名空间中的成员,你需要通过 NamespaceName.MemberName 的语法来访问它。

typescript
// 创建一个 LettersOnlyValidator 的实例
let validator = new Validation.LettersOnlyValidator();

console.log(validator.isAcceptable("HelloWorld")); // true
console.log(validator.isAcceptable("12345"));      // false

跨文件命名空间

命名空间可以跨越多个文件。只要多个文件中的命名空间同名,TypeScript 编译器就会将它们合并成一个单一的命名空间。这在组织大型项目时可能很有用。

Validators.ts

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

LettersOnlyValidator.ts

typescript
/// <reference path="Validators.ts" />
namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}

这里,/// <reference path="..." /> 是一个三斜杠指令,它告诉编译器文件之间的依赖关系。这是在模块系统出现之前,TypeScript 用来管理文件依赖的方式。

别名 (Alias)

为了简化对深层嵌套命名空间成员的访问,你可以使用 import 关键字为它们创建一个别名。

typescript
namespace Shapes {
    export namespace Polygons {
        export class Triangle { /* ... */ }
        export class Square { /* ... */ }
    }
}

// 创建一个别名
import Polygon = Shapes.Polygons;

let sq = new Polygon.Square(); // 使用别名

重要提示:这里的 import 与 ES6 模块中的 import 是不同的。它只用于为命名空间中的成员创建别名,并不会加载任何文件。

命名空间与模块的抉择

  • 命名空间: 主要用于组织全局作用域中的代码,通过 /// <reference> 来管理文件依赖。适合于没有模块加载器的传统 Web 应用开发。
  • 模块: 每个文件都是一个独立的模块,有自己的作用域。通过 importexport 来管理依赖关系。这是现代 JavaScript 和 TypeScript 开发的推荐方式,它与 Node.js 和打包工具(如 Webpack, Vite)的工作方式完全兼容。

总的来说,对于新项目,你应该优先使用模块。 只有在维护旧项目或与不使用模块的全局 JavaScript 库交互时,才需要深入了解命名空间。

本站内容仅供学习和研究使用。