8、typescript - 命名空间和模块的陷阱
对模块使用/// <reference>
一个常见的错误是使用/// <reference>
引用模块文件,应该使用import
。 要理解这之间的区别,我们首先应该弄清编译器是如何根据 import
路径(例如,import x from "...";
或import x = require("...")
里面的...
,等等)来定位模块的类型信息的。
编译器首先尝试去查找相应路径下的.ts
,.tsx
再或者.d.ts
。 如果这些文件都找不到,编译器会查找 外部模块声明。
回想一下,外部模块声明是在 .d.ts
文件里声明的。
myModules.d.ts
// In a .d.ts file or .ts file that is not a module: declare module "SomeModule" { export function fn(): string; }
- myOtherModule.ts
/// <reference path="myModules.d.ts" /> import * as m from "SomeModule";
这里的引用标签指定了外来模块的位置。 这就是一些TypeScript例子中引用
node.d.ts
的方法。
不必要的命名空间
如果你想把命名空间转换为模块,它可能会像下面这个文件一件:
shapes.ts
export namespace Shapes { export class Triangle { /* ... */ } export class Square { /* ... */ } }
顶层的模块
Shapes
包裹了Triangle
和Square
。 对于使用它的人来说这是令人迷惑和讨厌的:- shapeConsumer.ts
import * as shapes from "./shapes"; let t = new shapes.Shapes.Triangle(); // shapes.Shapes?
TypeScript里模块的一个特点是不同的模块永远也不会在相同的作用域内使用相同的名字。 因为使用模块的人会为它们命名,所以完全没有必要把导出的符号包裹在一个命名空间里。
再次重申,不应该对模块使用命名空间,使用命名空间是为了提供逻辑分组和避免命名冲突。 模块文件本身已经是一个逻辑分组,并且它的名字是由导入这个模块的代码指定,所以没有必要为导出的对象增加额外的模块层。