TypeScript中内部和外部模块之间的区别是什么?

时间:2012-10-11 14:10:20

标签: typescript

我花了一些时间阅读Typescript语言规范,并对内部外部模块之间的区别感到有些困惑。以下是直接从规范中进行的描述:

  

内部模块(第9.2.2节)是其他模块的本地或导出成员(包括全局模块和外部模块)。使用指定其名称和正文的ModuleDeclarations声明内部模块。具有多个标识符的名称路径等同于一系列嵌套的内部模块声明。

     

外部模块(第9.4节)是使用外部模块名称引用的单独加载的代码体。外部模块被编写为包含至少一个导入或导出声明的单独源文件。此外,可以使用全局模块中的AmbientModuleDeclarations声明外部模块,该模块直接将外部模块名称指定为字符串文字。这将在第0节中进一步描述。

根据我的理解,我认为外部模块对应于打字稿文件,而不包含简单地导出一组类型和/或变量的模块定义。从另一个打字稿文件,我可以使用import foo = module("foo");

foo.ts 中简单地导入外部模块

有人可以向我解释外部和内部模块之间的意图吗?

4 个答案:

答案 0 :(得分:27)

规范的第9.3和9.4节更清楚地解释了这一点。我将在这里重现这些部分中给出的一些例子。

外部模块

假设以下代码位于main.ts

import log = module("log");
log.message("hello");

此文件引用外部模块log,由log.ts导出。

定义
export function message(s: string) { 
  console.log(s); 
}

请注意,log.ts不会在任何地方使用module关键字。它只是导出export

内部模块

此文件有两个内部模块X.Y.Z

module A.B.C { 
  import XYZ = X.Y.Z; 
  export function ping(x: number) { 
    if (x > 0) XYZ.pong(x – 1); 
  }
} 
module X.Y.Z { 
  import ABC = A.B.C; 
  export function pong(x: number) { 
    if (x > 0) ABC.ping(x – 1); 
  } 
}

这些(主要)表现为外部模块,但它们包含在一个文件中,您不必引用任何外部文件来使用它们。在定义它们时,它们必须包含在module块内。

答案 1 :(得分:7)

根据Anders的演示文稿:http://channel9.msdn.com/posts/Anders-Hejlsberg-Introducing-TypeScript(34:40)和Typescript文档,外部模块是基于顶级AMD(异步模型定义)或CommonJS的模块。

外部模块在隐藏模块定义的内部语句并且仅显示与声明的变量关联的方法和参数时非常有用。

假设您有一个Main类,其中已定义log方法放在transfer.js文件中。只有在导入源js文件顶部的Main文件时,才会显示transfer.js类的内部方法:///<reference path="transfer.js"/>。这样编译器就可以在运行时消除所有js文件的遍历。

这是使用外部模块的巨大好处。另一个是当您尝试引用外部方法或类时,该方法或类在方法调用之后定义正常的自顶向下javascript流。使用外部模块,引用的类仅在方法调用时实例化。

答案 2 :(得分:1)

内部模块:

  1. 您可以在typescritp文件中定义模块。
  2. 模块中定义的所有变量都作用于模块,并从全局范围中删除。
  3. 编译打字稿文件时,模块会转换为必要时嵌套的变量,以形成类似命名空间的对象。请注意,使用IIFE(立即调用的函数表达式)整齐地隔离模块中定义的类。
  4. 下面的代码显示MyClass变量作用于MyInternalModule模块。它们无法在模块外部访问,这就是为什么代码的最后一行显示错误无法找到名称MyClass。
  5. 您可以使用export关键字访问模块外部的变量。
  6. 您还可以扩展内部模块,跨文件共享它们,并使用三重斜杠语法引用它们。(///)
  7. 示例

    module MyInternalModule{  
        class MyClass{               //if We write export keyword before the MyClass then last line works fine
            constructor (
                public height: number, 
                public width: number) {
        }
        }                   
        //working properly
        var obj1 = new MyClass(10, 4);
    }
    
    // it wont work //Because the out of the scope
    var obj2 = new MyInternalModule.MyClass(10,4) //shows error: can not find name MyClass
    

    打字稿的编译版本:

    var MyInternalModule;
    (function (MyInternalModule) {
        var MyClass = (function () {
            function MyClass(height, width) {
                this.height = height;
                this.width = width;
            }
            return MyClass;
        })();
        //working properly
        var obj1 = new MyClass(10, 4);
    })(MyInternalModule || (MyInternalModule = {}));
    

    外部模块:

    示例

    // bootstrapper.ts file
    
    // imports the greeter.ts file as the greeter module
    import gt = module('greeter');  
    export function run() {  
        var el = document.getElementById('content');
        var greeter = new gt.Greeter(el);
        greeter.start(); 
    }
    
    // greeter.ts file
    
    // exports the entire module
    export class Greeter {  
        start() {
             this.timerToken = setInterval(() => 
                 this.span.innerText = 
                 new Date().toUTCString(), 500);
        }
    }
    

答案 3 :(得分:0)

内部模块:namespacemodule关键字

声明

可以使用namespacemodule关键字声明内部模块。然后,我们可以使用export关键字来决定公开内部模块的哪一部分。

// LivingThings.ts
export namespace Animals {
    export class Dog { }
    export class Cat { }
}
export namespace Plants {
    export class Orchid { }
    export class Bamboo { }
}

// LivingThingsUser.ts
import { Animals, Plants } from "./LivingThings"

逻辑分组

在ES6之前,Typescript中使用了内部模块来封装接口,类,函数和变量,以支持一组相关功能并隐藏实现细节。这样,我们可以防止变量泄漏到全局空间中。这有助于更好的代码组织并防止名称冲突。 现在建议使用外部模块(ES6模块)来实现此目的。

内部模块现在用于环境名称空间声明。

单个文件的使用

我们可以在多个文件中声明内部模块,可以使用--outFile标志将它们串联。然后,我们可以在HTML页面的<script>标记内使用该级联文件。这样一来,我们就可以在包含所有依赖项的客户端Web应用程序中很好地构建代码。


外部模块:仅exportimport关键字

声明

外部模块也称为ES6模块。我们使用多个文件对相关功能进行分组,仅使用export关键字即可使所需对象公开可见。

// Animals.ts
export class Dog { }
export class Cat { }

// Plants.ts
export class Orchid { }
export class Bamboo { }

// LivingThingsUser.ts
import { Dog, Cat } from "./Animals"
import { Orchid, Bamboo } from "./Plants"

逻辑分组

通过使用单独的文件对相关功能进行分组来实现逻辑分组。因此,外部模块也称为文件模块

单个文件的使用

我们不使用<script>标签来加载客户端Web应用程序的外部模块,因为在下载这么多文件并同时渲染页面时,浏览器可能会变慢。为此,我们使用诸如CommonJS,AMD,SystemJS之类的模块加载器,这些模块加载器使我们能够异步加载文件或将外部模块文件连接到单个优化文件中。

对于服务器端,尤其是在Node.js中,强烈建议使用外部模块。


命名

为了声明内部模块,打字稿团队建议使用namespace { }而不是module { }语法,以避免与外部模块混淆。因为现在外部模块只是“模块”,而内部模块是“命名空间”。

就是这样!