Typescript 模块与命名空间-导入与需要类型脚本

Typescript 模块与命名空间-导入与需要类型脚本,typescript,Typescript,我对module/namespace/export和import、require、reference用法感到非常困惑。 作为Java背景的人,有人能简单地向我解释什么时候使用什么以及什么是正确的设计吗?当我在写样本项目时,我觉得自己搞砸了 到目前为止,这是我的理解 1. 模块用于外部软件包 2. 命名空间用于内部包 我不知道我们是怎么分类的 何时导出类、命名空间或包 如果我们导出包/名称空间,其中的所有类都将被导出或需要显式导出 如何导入/需要它们中的每一个 ,如果我为每个管理器/模型创建每

我对
module/namespace/export
import、require、reference
用法感到非常困惑。 作为Java背景的人,有人能简单地向我解释什么时候使用什么以及什么是正确的设计吗?当我在写样本项目时,我觉得自己搞砸了

到目前为止,这是我的理解 1. <代码>模块用于外部软件包 2. <代码>命名空间用于内部包

  • 我不知道我们是怎么分类的
  • 何时导出类、命名空间或包
  • 如果我们导出包/名称空间,其中的所有类都将被导出或需要显式导出
  • 如何导入/需要它们中的每一个
,如果我为每个管理器/模型创建每个“ts”文件,Typescript不建议使用“名称空间”?直接使用引用路径

请详细解释,因为我来自不同的背景,对ES6/ES5等不太清楚

我见过几个人提出同样的问题/对同样的问题感到困惑。我希望有人能详细解释现实世界的情况

  • 模块用于外部软件包2。命名空间用于内部包
  • 实际上,
    模块
    关键字已替换为
    名称空间
    关键字

    因此,更好的说法是,模块过去被称为外部模块,名称空间过去被称为内部模块

    更多 希望这能进一步帮助你:

    有两件事:

    • TypeScript中的模块是标准ES6概念,它在代码的顶层使用
      导入
      /
      导出
      关键字
    • 命名空间是TypeScript特有的概念,用于帮助以过时的方式组织代码
    名称空间 这几乎是一个过时的概念。在ES6模块之前,在浏览器中分离JavaScript代码的常用方法是创建全局变量。例如,像下划线这样的API的所有函数都位于名为
    \uuu
    的全局变量中

    这种老方法类似于Java包或PHP名称空间。它不适合网络。新的ECMAScript标准解决了以下问题:如何使用两个同名库?如何使用同一库的两个不同版本

    注意:在ECMAScript定义“模块”(2014年夏季)之前的TypeScript版本中,名称空间称为“内部模块”,模块称为“外部模块”

    注意2:
    名称空间中的关键字
    export
    是该关键字的非标准TypeScript用法。它是一种声明可从名称空间外部公开访问的对象的方法

    ES6模块 模块是一个文件,在代码的顶层包含关键字
    导入
    导出

    TypeScript遵循ECMAScript中的标准。我建议读一篇Mozilla的文章

    如果要在前端应用程序(在浏览器中)中使用模块,则必须使用绑定器([],Browserify)或加载程序([],RequireJS),并使用此环境配置TypeScript

    如果代码在Node.js中执行,只需配置TypeScript编译器以生成CommonJS格式

    注意:命名空间可以在模块中声明。在这种情况下,它将无法作为全局变量从模块外部访问。但是,它可以从模块中导出。

    我不知道如何对它们进行分类

    名称空间用于组织/封装代码。外部模块用于组织/封装代码,并在运行时定位代码。实际上,在运行时有两种选择:1)将所有传输的代码合并到一个文件中,或2)使用外部模块并拥有多个文件,并且需要其他一些机制来获取这些文件

    何时导出类、命名空间或包

    要使类型或值在其所在的文件外部可见,必须将其导出(如果它位于命名空间内部)。您是在顶级还是在命名空间中导出它将决定它现在是否在外部模块中

    如果我们导出包/名称空间,其中的所有类都将被导出或需要显式导出

    命名空间中的类始终需要显式导出,以便类在编译时在定义它的文件之外可见

    如何导入/需要它们中的每一个

    这取决于您是否使用外部模块。始终需要导入外部模块才能“使用”它。导入一个不在外部模块中的名称空间实际上只是为名称空间提供了一个别名——您仍然必须使用别名作为类型/任何内容的前缀(这就是为什么您通常不希望在外部模块中使用名称空间;这样做意味着您在引用外部模块提供的任何内容时始终必须使用前缀。)不在外部模块中的名称空间可以跨文件,因此如果您在同一名称空间中,则可以引用名称空间导出的任何内容,而无需任何类型的导入

    要真正理解上述内容,您需要一些背景知识。理解引用/名称空间/外部模块的关键是这些构造在编译时做什么以及在运行时做什么

    引用指令在编译时用于定位类型信息。您的源代码中有一个特定的符号。TypeScript编译器如何定位该符号的定义?引用指令主要包含在tsconfig.json机制中——使用tsconfig.json,您可以告诉编译器所有源代码的位置

    名称空间可以包含类型定义和/或实现。如果名称空间只包含类型信息,那么它根本没有运行时显示——您可以通过查看JS输出并查找
    namespace MyApp {
    
        // without an export the interface is not visible outside of MyService.ts
        export interface MyService { 
            ....
        }
    
        // class is not exported; AngularJS DI will wire up the implementation
        class MyServiceImpl implements MyService {
        }
    
        angular.module("MyApp").service("myService", MyServiceImpl);
    }
    
    namespace MyApp {
    
       class MyController {
           // No import of MyService is needed as we are spanning 
           // one namespace with multiple files.
           // MyService is only used at compile time for type checking. 
           // AngularJS DI is done on the name of the variable. 
           constructor(private myService: MyService) { 
           }
       }
       angular.module("MyApp").controller("myController", MyController);
    }
    
    namespace Foo {
        // without an export IFoo is not visible. No JS is generated here
        // as we are only defining a type.
        export interface IFoo {
            x: string;
        }
    }
    
    interface ITopLevel {
        z: string;
    }
    
    (function(){
        // export required above to make IFoo visible as we are not in the Foo namespace
        class Foo1 implements Foo.IFoo {
            x: string = "abc";
        }
        // do something with Foo1 like register it with a DI system
    })();
    
    // alias import; no external module created
    import IFoo = Foo.IFoo;
    
    (function() {
    
        // Namespace Foo is always visible as it was defined at
        // top level (outside of any other namespace).
        class Bar1 implements Foo.IFoo {
            x: string;
        }
    
        // equivalent to above
        class Bar2 implements IFoo {
            x: string;
        }
    
        // IToplevel is visible here for the same reason namespace Foo is visible
        class MyToplevel implements ITopLevel {
            z: string;
        }
    
    })();
    
    interface MyService { 
        ....
    }
    
    (function() {
    
        class MyServiceImpl implements MyService {
        }
    
        angular.module("MyApp").service("myService", MyServiceImpl);
    })();
    
    (function() { 
    
       class MyController { 
           constructor(private myService: MyService) { 
           }
       }
    
       angular.module("MyApp").controller("myController", MyController);
    })();
    
    // 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"
    
    // 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"