打字稿中的命名空间和模块混乱?

Alb*_*Gao 5 theory namespaces module typescript

Typescript的官方网站让我问一个问题,“我们是否需要使用名称空间?”。

以下引用很好地解释了两件事:

请务必注意,在TypeScript 1.5中,术语已更改。“内部模块”现在是“命名空间”。为了与ECMAScript 2015的术语保持一致,“外部模块”现在仅是“模块”(即模块X {等同于现在首选的命名空间X {)。

因此,他们建议TS团队更喜欢命名空间。此外,它说我们应该使用“命名空间”来构造内部模块:

这篇文章概述了使用TypeScript中的名称空间(以前称为“内部模块”)组织代码的各种方法。正如我们在有关术语的注释中提到的那样,“内部模块”现在称为“命名空间”。另外,在声明内部模块时,在使用module关键字的任何地方,可以并且应该改用namespace关键字。这样可以避免给新用户添加名称相似的术语,从而使他们感到困惑。

上面的引文全部来自“命名空间”部分,是的,它再次说了,但是是内部的。
但在模块部分的一段中说:

从ECMAScript 2015开始,模块是语言的本机部分,并且所有兼容引擎实现均应支持该模块。因此,对于新项目,模块将是推荐的代码组织机制。

这是否意味着我不需要打扰命名空间,始终使用模块是建议的开发方式?

The*_*ung 2

这是否意味着我不需要担心命名空间,一直使用模块是建议的开发方式?

我不会这么说……这是对所发生事情的另一个解释。曾几何时,Typescript 中使用了两个术语

  1. “外部模块” - 这是 TS 与 JS 社区称为 AMD(例如 RequireJS)或 CommonJS(例如 NodeJS)模块的类似物。这是可选的,对于一些只编写基于浏览器的代码的人来说,他们并不总是为此烦恼,特别是当他们使用全局变量跨文件进行通信时。
  2. “内部模块” - 这是组织变量/函数的分层方式,因此并非所有内容都是全局的。JS 中也存在同样的模式,人们将变量组织成对象/嵌套对象,而不是让它们全部全局化。

Ecmascript 2015(又名 ES6)随之而来,它添加了一种属于“外部模块”类别的新的正式标准格式。由于这一变化,Typescript 希望更改术语以匹配新的 Javascript 标准(因为它希望成为 Javascript 的超集,并尽力避免来自 Javascript 的用户感到困惑)。因此,“外部模块”的切换被简化为“模块”,而“内部模块”被重命名为“命名空间”。

您在这里找到的引用:

从 ECMAScript 2015 开始,模块是该语言的本机部分,并且应该受到所有兼容引擎实现的支持。因此,对于新项目,模块将是推荐的代码组织机制。

可能暗指尚未使用(外部)模块的用户的指导。至少现在考虑使用它。然而,对 ES6 模块的支持仍然不完整,因为截至 2016 年 5 月,浏览器还没有内置模块加载器。因此,您要么必须添加一个polyfill(在运行时处理它),如RequireJS或SystemJS,要么添加一个在构建时(在部署到您的网站之前)处理它的捆绑器(如browserify或webpack)。

那么,您会同时使用模块(以前的“外部模块”)和命名空间吗?绝对 - 我在我的代码库中经常使用它们。我使用(外部)模块来组织我的代码文件。

命名空间非常有用。具体来说,我使用名称空间声明合并作为一种类型安全的方式来向函数对象本身添加额外的属性(JS 中经常使用的模式)。此外,虽然命名空间很像常规对象变量,但您可以将子类型(嵌套接口、类、枚举等)挂在其名称之外。

下面是一个带有属性的函数的示例(在 NodeJS 库中很常见):

function someUsefulFunction() {
  // asynchronous version
  return ...; // some promise
}

namespace someUsefulFunction {
  export function sync() {
    // synchronous version
  }
}
Run Code Online (Sandbox Code Playgroud)

这允许消费者执行这种常见的 NodeJS 模式:

// asynchronous consumer
someUsefulFunction()
  .then(() => {
    // ... 
  });

// synchronous consumer
someUsefulFunction.sync();
Run Code Online (Sandbox Code Playgroud)

同样,假设您有一个接受选项对象的 API。如果该选项类型特定于该 API,

function myFunc(options?: myFunc.Options) {
    // ...
}

namespace myFunc {
    export interface Options {
        opt1?: number;
        opt2?: boolean;
        opt3?: string;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您不必使用选项的类型声明来污染更大的名称空间(例如整个模块范围)。

希望这可以帮助!