关于术语的一点说明: TypeScript 1.5 里, “内部模块”现在称做“命名空间”,“外部模块”现在则简称为“模块”。
在 JavaScript
中,我们需要一种手段来组织代码,以防止对象之间产生命名冲突。 因此,我们把代码包裹到一个个命名空间内,而不是把它们放在全局命名空间下,可以有效避免全局污染。
虽然在 ES6
中引入了模块系统后,不需要再考虑全局污染问题,但当我们使用全局类库时,命名空间依然是个比较好的解决方案。
使用
-
a.ts
namespace Shape { const pi = Math.PI; export function circle(r: number) { return pi * r ** 2; } export interface Person { name: string; age: number; } }
命名空间内可以定义若干变量,这些变量只在命名空间下可见;如果想要在全局使用,可以使用 export
。
分离到多文件
随着程序变大,命名空间也可以进行拆分。
- b.ts
/// <reference path='./a.ts' /> namespace Shape { export function square(w: number) { return w * w; } }
虽然在不同的文件中,但他们是同一个命名空间,使用时就如同定义在一个文件中的命名空间一样使用。 因为不同文件间存在引用关系,所以要用引用标志告诉编辑器文件之间的关联。
/// <reference path='a.ts'/>
当涉及到多文件时,我们必须确保所有编译后的代码都被加载了。
-
方法一:
把所有的输入文件编译为一个输出文件,需要使用
--outFile
标记:tsc --outFile sample.js Test.ts
编译器会根据源码里的引用标签自动地对输出进行排序。
-
方法二:
每个源文件都会对应生成一个
JavaScript
文件。 然后,在页面上通过<script>
标签把所有生成的JavaScript
文件按正确的顺序引进来,<script src="Test.js" type="text/javascript" /> <script src="a.js" type="text/javascript" /> <script src="b.js" type="text/javascript" />
别名
使用 import q = x.y.z
给常用的对象起一个短的名字,可以简化命名空间操作。
namespace Shape {
export function square(w: number) {
return w * w;
}
}
import square = Shape.square;
square(); // same as "Shape.square()"
不要与用来加载模块的 import x = require('name')
语法弄混了,这里的语法是为指定的符号创建一个别名。 你可以用这种方法为任意标识符创建别名,也包括导入的模块中的对象。
最后
命名空间和模块不要混用,像命名空间一样,模块可以包含代码和声明。不同的是模块可以声明它的依赖。
模块会把依赖添加到模块加载器上(例如CommonJs
/ Require.js
)。这会带来长久的模块化和可维护性上的便利。模块也提供了更好的代码重用,更强的封闭性以及更好的使用工具进行优化。
对于 Node.js
应用来说,模块是默认并推荐的组织代码的方式。
从 ES6
开始,模块成为了语言内置的部分,应该会被所有正常的解释引擎所支持。 因此,对于新项目来说推荐使用模块做为组织代码的方式。ts
保留命名空间,更多的考虑是对全局变量时代的兼容。