TypeScript 中的命名空间与模块

理解 TypeScript 命名空间和模块的概念及使用场景

问题

TypeScript 中命名空间(namespace)与模块(module)有什么区别?分别在什么场景下使用?

解答

模块

TypeScript 与 ES2015 一样,任何包含顶级 importexport 的文件都被视为一个模块。

如果文件不包含顶级的 importexport 声明,其内容会被视为全局可见。例如在 1.ts 中声明变量:

const a = 1

在另一个文件中再次声明同名变量会报错,因为它们都在全局作用域中。

通过 export 引入模块系统可以解决这个问题:

const a = 10;
export default a

模块可以导出变量、类型等:

export const a = 1
export type Person = {
    name: string
}

通过 import 引入模块:

import { a, Person } from './export';

命名空间

命名空间用于解决命名冲突问题,将相关的全局变量组织到一个对象中。

使用 namespace 关键字定义,需要导出的成员要添加 export

namespace SomeNameSpaceName {
   export interface ISomeInterfaceName { }
   export class SomeClassName { }
}

使用方式:

SomeNameSpaceName.SomeClassName

命名空间本质上是一个对象:

namespace Letter {
  export let a = 1;
  export let b = 2;
  export let c = 3;
}

编译后的 JavaScript:

var Letter;
(function (Letter) {
    Letter.a = 1;
    Letter.b = 2;
    Letter.c = 3;
})(Letter || (Letter = {}));

区别与使用建议

命名空间是全局命名空间下的一个普通 JavaScript 对象,在大型应用中难以识别组件间的依赖关系。

模块可以明确声明依赖关系,更适合现代 TypeScript 项目开发。

在实际开发中,推荐使用模块而非命名空间。命名空间主要用于编写 .d.ts 声明文件,为 JavaScript 库标记类型。

关键点

  • 模块通过 import/export 声明,具有独立作用域,可明确声明依赖关系
  • 命名空间使用 namespace 定义,本质是全局对象,用于组织相关变量
  • 现代 TypeScript 项目推荐使用模块,命名空间主要用于类型声明文件
  • 没有顶级 import/export 的文件内容会被视为全局可见