TypeScript - 命名空间
TypeScript - 命名空间
Section titled “TypeScript - 命名空间”命名空间(Namespaces)是 TypeScript 中一种特定的代码组织方式,通过将逻辑相关的功分组来避免污染全局作用域和防止命名冲突,尤其是在大型应用程序中。在标准 ES 模块(import/export)广泛采用之前,它们尤为重要。
建议: 对于大多数现代 TypeScript 项目,ES 模块(import/export)是代码组织和依赖管理的首选标准。命名空间现在不太常见,但仍然存在,并且在特定场景下可能有用。
何时考虑使用命名空间
Section titled “何时考虑使用命名空间”- 遗留代码库: 你可能会在较旧的 TypeScript 项目中遇到它们。
- 组织内部代码: 有时用于大型库或应用程序内部,将内部帮助函数或组件分组,而不将其作为单独的模块暴露。
- 增强全局对象: 在声明文件(
.d.ts)中使用,为现有的全局对象或库添加属性或方法。 - 简单脚本 /
--outFile: 当使用tsc --outFile选项将多个.ts文件编译成一个单独的 JavaScript 输出文件时(在使用模块系统时较少见)。
定义命名空间
Section titled “定义命名空间”命名空间定义以 namespace 关键字开头,后跟命名空间名称。任何打算在命名空间外部使用的内容都必须使用 export 关键字明确导出。
// --- validationUtils.ts ---namespace Validation { export interface StringValidator { isValid(s: string): boolean; }
// 内部细节,未导出 const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;
export class EmailValidator implements StringValidator { isValid(s: string): boolean { return emailRegex.test(s); } }
export function isString(value: any): value is string { return typeof value === 'string'; }}访问命名空间成员
Section titled “访问命名空间成员”要从命名空间外部访问导出的成员,使用命名空间名称后跟一个点(.)和成员名称。
// --- app.ts ---
// 假设 validationUtils.ts 已编译/包含
const email = "test@example.com";const validator: Validation.StringValidator = new Validation.EmailValidator();
if (validator.isValid(email)) { console.log(`'${email}' 是一个有效的电子邮件地址。`);} else { console.log(`'${email}' 不是一个有效的电子邮件地址。`);}
console.log(`'hello' 是一个字符串吗? ${Validation.isString('hello')}`); // true// console.log(Validation.emailRegex); // 错误:属性 'emailRegex' 未从命名空间 'Validation' 中导出。多文件命名空间
Section titled “多文件命名空间”命名空间可以跨越多个文件。TypeScript 将在不同文件中声明的同名命名空间视为合并。为了确保编译器在不使用 ES 模块时了解文件之间的依赖关系,你通常需要:
- 三斜线引用指令:
/// <reference path="./other-file.ts" />放在依赖文件的顶部。 - 编译顺序或
--outFile: 确保文件以正确的顺序编译,或使用tsc --outFile output.js file1.ts file2.ts ...打包成一个文件(注意:--outFile需要tsconfig.json中设置"module": "System"或"AMD",并且与CommonJS、ESNext等不兼容)。
示例:多文件命名空间
Section titled “示例:多文件命名空间”// --- interfaces.ts ---namespace MyShapes { export interface Shape { getArea(): number; }}
// --- circle.ts ---/// <reference path="interfaces.ts" />namespace MyShapes { export class Circle implements Shape { constructor(public radius: number) {} getArea(): number { return Math.PI * this.radius ** 2; } }}
// --- rectangle.ts ---/// <reference path="interfaces.ts" />namespace MyShapes { export class Rectangle implements Shape { constructor(public width: number, public height: number) {} getArea(): number { return this.width * this.height; } }}
// --- main.ts ---/// <reference path="circle.ts" />/// <reference path="rectangle.ts" />
const circle = new MyShapes.Circle(5);const rect = new MyShapes.Rectangle(10, 4);
console.log(`圆形面积: ${circle.getArea()}`);console.log(`矩形面积: ${rect.getArea()}`);
// 使用以下命令编译: tsc --outFile dist/app.js main.ts同样,这种多文件设置通过 ES 模块可以更优雅地处理,而无需引用指令或 --outFile。
嵌套命名空间
Section titled “嵌套命名空间”你可以在其他命名空间内部定义命名空间。
namespace App { export namespace Services { export class ApiClient { fetchData() { console.log('正在获取数据...'); } } } export namespace Utils { export function log(message: string) { console.log(`日志: ${message}`); } }}
const client = new App.Services.ApiClient();client.fetchData();App.Utils.log("应用程序已启动。");命名空间别名
Section titled “命名空间别名”你可以使用 import alias = Namespace.NestedNamespace; 为嵌套的命名空间创建更短的别名。
import ServiceClient = App.Services.ApiClient;import logUtil = App.Utils.log;
const client2 = new ServiceClient();logUtil("正在使用别名。");注意:这种 import = 语法专门用于导入命名空间和旧的模块格式,与标准的 ES import 关键字不同。
虽然命名空间是早期 TypeScript 的重要组成部分,但 ES 模块(import/export)为现代 JavaScript 和 TypeScript 中的代码组织提供了一种标准化、更强大且更广泛采用的机制。请谨慎使用命名空间,主要是在与遗留系统或特定的声明文件模式交互时。