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

时间:2016-05-16 17:11:34

标签: module typescript namespaces theory

打字稿的官方网站让我问一个问题, "我们是否需要使用命名空间?"。

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

  

重要的是要注意在TypeScript 1.5中,命名法有   改变。 “内部模块”现在是“命名空间”。 “外部模块”   现在只是“模块”,以配合ECMAScript 2015   术语,(即模块X {相当于   now-preferred命名空间X {)。

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

  

本文概述了使用组织代码的各种方法   TypeScript中的命名空间(以前称为“内部模块”)。和我们一样   我们在关于术语的说明中提到了“内部模块”   被称为“命名空间”。此外,模块关键字的任何位置   在声明内部模块时使用,namespace关键字可以   而应该用来代替。这可以避免让新用户感到困惑   使用类似命名的术语重载它们。

以上引用全部来自Namespace部分,是的,它再次说明,但是在内部secnario中。
但在模块部分,有一段说:

  

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

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

1 个答案:

答案 0 :(得分:1)

  

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

我不会那么说......这是对发生的事情的另一种解释。有一次,在Typescript中使用了两个术语

  1. “外部模块” - 这是与JS社区称为AMD(例如RequireJS)或CommonJS(例如NodeJS)模块的TS类似。这是可选的,对于一些只编写基于浏览器的代码的人来说,他们并不总是为此烦恼,特别是如果他们使用全局变量来跨文件进行通信。
  2. “内部模块” - 这是一种组织变量/函数的分层方式,因此并非所有内容都是全局的。 JS中存在相同的模式,当人们将变量组织到对象/嵌套对象中而不是将它们全局化时。
  3. 沿着Ecmascript 2015(a.k.a。ES6),它添加了属于“外部模块”类别的新的正式标准格式。由于这种变化,Typescript希望改变术语以匹配新的Javascript标准(因为它喜欢成为Javascript的超集,并尽力避免混淆来自Javascript的用户)。因此,“外部模块”的切换被简化为“模块”,“内部模块”被重命名为“命名空间”。

    你在这里找到的引用:

      

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

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

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

    Typescript中的

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

    以下是具有属性的函数示例(在NodeJS库中非常常见):

    function someUsefulFunction() {
      // asynchronous version
      return ...; // some promise
    }
    
    namespace someUsefulFunction {
      export function sync() {
        // synchronous version
      }
    }
    

    这允许消费者使用这种常见的NodeJS模式:

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

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

    function myFunc(options?: myFunc.Options) {
        // ...
    }
    
    namespace myFunc {
        export interface Options {
            opt1?: number;
            opt2?: boolean;
            opt3?: string;
        }
    }
    

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

    希望这有帮助!