模块与命名空间 - 导入与需要 Typescript

2024-01-03

我很困惑module/namespace/export and import, require, reference用法。 来自 Java 背景,有人可以简单地解释一下我何时使用什么以及什么是正确的设计?当我编写示例项目时,我觉得我搞砸了

到目前为止这是我的理解 1.module用于外部包 2.namespace用于内部包

  • 我不明白我们如何分类?
  • 何时导出类、命名空间或包?
  • 如果我们导出包/命名空间,则其中的所有类都会被导出或需要显式导出
  • 如何导入/需要其中每一项?

根据文件 https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html,如果我为每个经理/模型创建每个“ts”文件,Typescript 不建议使用“命名空间”?直接使用参考路径?

请详细解释一下,因为我来自不同的背景,不确定 ES6/ES5 等。

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


我不明白我们如何分类?

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

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

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

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

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

如何导入/需要其中每一项?

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

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

引用指令在编译时用于定位类型信息。您的来源中有一个特定的符号。 TypeScript 编译器如何找到该符号的定义?引用指令很大程度上已包含在 tsconfig.json 机制中——使用 tsconfig.json,您可以告诉编译器您的所有源代码在哪里。

命名空间可以包含类型定义和/或实现。如果命名空间仅包含类型信息,那么它根本没有运行时表现——您可以通过查看 JS 输出并找到一个空 JS 文件来检查这一点。如果命名空间具有实现代码,则代码将包装在闭包内,该闭包被分配给与命名空间同名的全局变量。对于嵌套命名空间,根命名空间将有一个全局变量。再次检查 JS 输出。历史上,命名空间是 JS 客户端库试图避免命名冲突问题的方式。这个想法是将整个库包装到一个闭包中,然后暴露尽可能小的全局足迹——只有一个引用该闭包的全局变量。好吧,问题仍然是你已经在全球空间中拥有了自己的名字。比如说,如果您想要一个库的两个版本怎么办? TypeScript 命名空间仍然存在如何定位命名空间源的问题。也就是说,引用 A.B 的源代码仍然存在告诉编译器如何定位 A.B 的问题 - 通过使用引用指令或使用 tsconfig.json。或者将命名空间放入外部模块中,然后导入外部模块。

外部模块起源于服务器端 JS。外部模块和文件系统上的文件之间存在一一对应的关系。您可以使用文件系统目录结构将外部模块组织成嵌套结构。导入外部模块通常会引入对该外部模块的运行时依赖(例外情况是当您导入外部模块但随后不在值位置使用其任何导出时——也就是说,您只导入外部模块获取其类型信息)。外部模块隐式地存在于闭包中,这是关键:模块的用户可以将闭包分配给他们想要的任何局部变量。 TypeScript/ES6 添加了额外的语法来将外部模块的导出映射到本地名称,但这只是一个好处。在服务器端,定位外部模块相对简单:只需在本地文件系统上定位表示外部模块的文件即可。如果您想在客户端、浏览器中使用外部模块,情况会变得更加复杂,因为没有与可用于加载模块的文件系统等效的文件系统。因此,现在在客户端,您需要一种方法将所有这些文件捆绑成可以在浏览器中远程使用的形式 - 这就是像 Webpack 这样的模块捆绑器(尽管 Webpack 所做的事情比捆绑模块要多得多)和Browserify 开始发挥作用。模块捆绑器允许在浏览器中运行时解析外部模块。

现实世界场景:AngularJS。假装外部模块不存在,使用单个命名空间来限制全局空间的污染(在下面的示例中,单个变量 MyApp 是全局空间中的全部),仅导出接口,并使用 AngularJS 依赖注入来进行实现可供使用。将所有类放在根目录中,将 tsconfig.json 添加到根目录,在同一根目录下安装 angularjs 类型,以便 tsconfig.json 也选择它,将所有输出合并到一个 JS 文件中。如果代码重用不是很重要的话,这对于大多数项目来说都可以正常工作。

我的服务.ts:

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);
}

我的控制器.ts:

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);
}

使用 IIFE 避免污染全局运行时范围。在此示例中,根本没有创建任何全局变量。 (假设有 tsconfig.json。)

Foo.ts:

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
})();

Bar.ts:

// 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;
    }

})();

使用 IIFE,您可以消除在第一个示例中引入 MyApp 作为全局变量的情况。

我的服务.ts:

interface MyService { 
    ....
}

(function() {

    class MyServiceImpl implements MyService {
    }

    angular.module("MyApp").service("myService", MyServiceImpl);
})();

我的控制器.ts:

(function() { 

   class MyController { 
       constructor(private myService: MyService) { 
       }
   }

   angular.module("MyApp").controller("myController", MyController);
})();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模块与命名空间 - 导入与需要 Typescript 的相关文章

随机推荐

  • Elastic Search - 用于内部命中的 java api

    我做了一些查询 如下所示 query nested path comments votes query inner hits 我将它转换为java api QueryBuilders boolQuery must boolQuery mus
  • 为不同的语言环境定制 java.text 格式化程序

    构建一个支持不同语言环境的 java 应用程序 但想要自定义DateFormat显示超出之间可用的内容FULL LONG MEDIUM and SHORT日期格式选项 想做一些事情 比如在日期和时间部分之间放置一个字符DateFormat
  • 索引 0 {} 处缺少参数名称

    我尝试写一个演示 交付演示 https github com CIeNET Corda deliverydemo基于训练营cordapp https github com corda bootcamp cordapp并参考cordapp 示
  • 使用反射更改只读属性

    是否可以 通过反思还是其他方式 正如其他人所说 如果您需要这样做 那么您首先将面临设计问题 现在 如果你想知道这是否可能只是为了了解 或者如果地球上没有其他方法可以做到这一点 那么在一个非常小的帮助下 这确实是可能的辅助库 http git
  • 如何将数据文件包含在应用程序的 APK 中?

    我想在安装 Android 应用程序时创建一些预先创建的文件 我想在内部存储器 data data files 和新创建的 sdcard 目录 sdcard data1 中创建文件 我怎样才能做到这一点 如果您有大量文件和目录结构 则应使用
  • 如何使用 Stylish 或 Greasemonkey 替换 @media (max-width)?

    我在查看时遇到问题这个网站 http www fleaflicker com nfl 在我的桌面浏览器上 它们采用响应式 流畅设计 当浏览器宽度小于 990 像素时 显示移动菜单按钮而不是水平导航栏 由于我使用的是 125 缩放的 Fire
  • 如何在pandas中创建日历表(日期维度)

    数据库设计中有时会使用带有主键的日期表 date id Date Record timestamp Day Week Month Quarter Year half Year 0 2000 01 01 NaN Saturday 52 1 1
  • Django:db_index 和 makemigrations

    我想在模型中的现有字段中添加一些 db index 我刚刚添加了db index True到模型 我想我需要跑步python manage py migrate将它们应用到数据库上 我的问题是没有检测到任何更改 因此没有创建迁移 这是正常行
  • 使用 python 和 OpenCV 从图像中提取数字

    我正在寻找一些编码解决方案 帮助从液晶显示屏中提取数字 然后从图像中输出值 下面是代码和示例图像以及到目前为止我是如何得到的 但我需要一些进一步的帮助来实际从图像中提取 数字 并输出值 我从前面的例子中制作了数字查找表 import the
  • 尝试加载字体时出现 GD 错误

    我尝试通过以下方式加载字体图像加载字体 http www php net manual en function imageloadfont php功能 当我运行脚本时 我收到错误 gd warning product of memory a
  • R语言,暂停循环并要求用户继续

    我有一个想法在某些迭代中暂停循环并向 用户 询问一些答案 例如 some value 0 some criteria 50 for i in 1 100 some value some value i if some value gt so
  • 如何捕获无效的用户输入[关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我不理解 Try throw catch 语句 并且想知道当代码中的所有 put 都应该是 int 时 捕获 char 的最佳方式是什么 这
  • TableView 单元格分隔线未延伸到整个单元格

    我正在开发一个新项目 并在 UI 中使用了故事板 我的所有 tableView 都存在行分隔符问题 下图显示了两条线 第一个是在属性检查器中设置的蓝色 第二个是黑色的 添加了我放置在单元格中的 imageView 该线确实延伸到单元格的右侧
  • 如何在 Java 中连接两个列表?

    有没有比以下更简单的方法 List
  • 无需分组即可获得最大值

    假设我有一张这样的表 name age a 1 b 2 c 3 d 4 e 5 f 6 通常 当我们选择 MAX age 时 它返回 f 6 元组 但我想要的是它应该按原样返回表 但所有年龄值都将是最大值 例如 name age a 6 b
  • 使用 Flyway 管理修补程序

    假设我有 2 个分支 Develop与迁移 V1 change1 V2 change2 V3 change3 V4 change4 V5 change5 Master迁移 部署在生产环境中 V1 change1 V2 change2 现在我
  • 如何在 jetpack compose 中显示具有适当大小/布局的垂直文本

    如何在 jetpack 中正确旋转文本并使其进行正确的布局 当我使用rotate文本对象上的修饰符会旋转文本 但布局中占用的大小似乎使用预旋转的文本宽度 这是我想要完成的一个简单示例 垂直文本应该位于狭窄空间的左侧 Composable f
  • 使用 groovy 将 ISO-8859-1 转换为 UTF-8

    我需要将 ISO 8859 1 文件转换为 utf 8 编码 而不丢失内容信息 我有一个如下所示的文件
  • 如何在 Python 中使用 AsciiDoc?

    最初的 AsciiDoc 处理器是用 python 编写的 但 AsciiDoc 演变为用 Ruby 编写的 Asciidoctor 形式 在我搜索如何处理现代 AsciiDoc Asciidoctor 方言 时 我只看到一篇文章 说有一个
  • 模块与命名空间 - 导入与需要 Typescript

    我很困惑module namespace export and import require reference用法 来自 Java 背景 有人可以简单地解释一下我何时使用什么以及什么是正确的设计 当我编写示例项目时 我觉得我搞砸了 到目前