繁体   English   中英

TypeScript 模块导入和 WebPack

[英]TypeScript Module Importing & WebPack

我在让 WebPack 为用 TypeScript 编写的项目注入导入的依赖项时遇到了一些麻烦。 我的第一个问题是让 TypeScript 识别导入的模块。

我有一个header.ts文件,它声明了一个嵌套在vi.input下的模块,并导出了一个VIInputDirective类。 main.ts文件中,我尝试从header.ts文件导入导出的VIInputDirective类,但似乎无法让 TypeScript 识别它。

头文件

module vi.input.header {
  import IDirective = angular.IDirective;

  export class VIInputDirective implements IDirective {
    ...
  }
}

主文件

import {VIInputDirective} from "./header.ts"; // Nothing imported; Cannot Resolve issue
VIInputDirective.whatever(); // Does not work

材料.dt.s

declare module vi.input {
  ...
}

如果我交换import {VIInputDirective} from "./header.ts"; main.ts文件中使用import VIMHeaderDirective = vi.input.header.VIInputDirective; 它工作正常,但是 webpack 在 transpile/inject 上给了我以下错误:

VM1469:1Uncaught ReferenceError: vi is not defined

我试过直接导出vi.input.header模块(即导出模块 vi.input.header),但没有奏效。 我还尝试使用参考 sytnax 来包含文件,但这也不起作用: ///<reference path="file_path"/>

这是模块嵌套的问题,因为如果我删除模块并直接导出 VIInputDirective 类,它可以正常工作。 但是,我想将它保留在嵌套模块中。

您没有使用模块。 模块具有一个或多个顶级importexport语句。 相反,您正在使用全局命名空间并创建全局命名空间的子命名空间来组织您的程序。 这称为揭示模块模式。 它不涉及使用模块。

不幸的是,TypeScript 过去常常将这种模式称为使用内部模块 此术语已被弃用,并且强烈建议不要使用module x {}语法(注意x周围缺少" s )。该语言引入了同义关键字namespace ,以减少混淆。

JavaScript 加载器和打包器(如 Webpack、RequireJS 和 SystemJS)与模块一起工作,这就是 TypeScript 所说的外部模块

为了澄清你提到与模块有关以下构造

  1. 顶级非导出module / namespace语法声明

    module vi.input.header { ... }

    这现在可以写成

    namespace vi.input.header { ... }

    为了尽量减少混淆,但无论如何,发射总是导致。

     var vi; (function (vi) { var input; (function (input) { var header; (function (header) { })(header = input.header || (input.header = {})); })(input = vi.input || (vi.input = {})); })(vi || (vi = {}));

    请注意,这会以各种库常用的模式改变全局范围。 namespace (以前称为内部模块)有一个有趣的特性,即多个文件可以为其内容做出贡献,而这实际上是它们的主要目的。 这解释了上面发射中的嵌套程度和对变量的条件赋值。 这与使用Modules无关。

  2. import引用namespace成员的赋值,例如

    import IDirective = angular.IDirective;

    不符合顶级import声明的条件,因此不会导致它们的包含文件被视为模块。 即使它们位于文件的顶层也是如此。 原因是模块系统,无论是 AMD、CommonJS、System 还是 ES2015,使用字符串作为模块说明符,从这些字符串导入; 顺便说一下,它可能代表文件路径、url、解析的简单名称或合成模块 ID。

同样,代码中的import name = qualified.global.name语句是与Modules无关的 TypeScript 特定功能。 它们对于嵌套类型和值的别名非常有用,但它们不制作模块。

现在,这里是它变得有趣,并在那里与您的具体问题相交namespace s可以使用,而且有时相当漂亮,从外部模块,但它们的语义有很大的不同

考虑

服务.ts

export namespace app {
  export class SomeService { }
}

编译成以下 JavaScript

export var app;
(function (app) {
    class SomeService {
    }
    app.SomeService = SomeService;
})(app || (app = {}));

主文件

export namespace app {
  export function bootstrap() { }
}

编译成以下 JavaScript

export var app;
(function (app) {
    function bootstrap() { }
    app.bootstrap = bootstrap;
})(app || (app = {}));

以上两个都是外部模块,也就是真正的模块,它们使用命名空间作为内部代码组织机制,但它们的关键在于它们构成共享app命名空间,每个命名空间都有自己的文件范围的app变量。 两者都没有对对方成员的隐式访问, namespace app的声明不会跨文件合并,并且它们具有类似的内部命名方案是它们的模块化附带的。

那么所有这些与您的问题和您尝试应用的建议有何关系?

让我们看看

头文件.ts

module vi.input.header {
  import IDirective = angular.IDirective;

  export class VIInputDirective implements IDirective {
    static whatever() { }
  }
}

如上所述,该文件不是模块,而是使用全局命名空间来公开其声明。 如果我们今天写这个,按照惯例,我们会使用namespace关键字而不是module关键字。

主文件

import {VIInputDirective} from "./header.ts"; // Nothing imported; Cannot Resolve issue
VIInputDirective.whatever(); // Does not work

确实,这两行都不行,因为您将headers.ts当作模块导入,但正如我们刚刚看到的,它不是模块。 此外,具有讽刺意味的是,第一行是从模块说明符字符串import的顶级import语句,它使main.ts本身成为一个模块。

简而言之,这两种风格不能很好地混合,并且在它们之间共享代码并不简单,也不是您应该尝试做的事情(我已将 UMD 格式排除在此答案之外,以使其相对简单)。

现在我们回到了原点

强文本

declare module vi.input {
    ....
}

如果我交换 import {VIInputDirective} from "./header.ts"; 在 main.ts 文件中使用 import VIMHeaderDirective = vi.input.header.VIInputDirective; 它工作正常,但是 webpack 在 transpile/inject 上给了我以下错误:

确实如上文所述。 import不针对模块说明符字符串,并且没有任何其他顶级导入或导出,更改main.ts使其不再是模块。 这会导致 TypeScript 正确地对其进行类型检查,使用import = namespace.value相互引用的全局变量是完全合法的,但这些不是模块和 JavaScript 工具,例如 Webpack,对模块进行操作。

那么,在这个美丽的新世界中,您将如何编写这个应用程序? 由于您使用的是模块捆绑工具 Webpack,因此您可以一直使用适当的模块来编写它。

主文件

import {VIInputDirective} from "./header.ts";
VIInputDirective.whatever();

头文件.ts

import {IDirective} from 'angular';

export class VIInputDirective implements IDirective {
  static whatever() { }
}

material.d.ts不再像您编写此文件时那样,因为它已更新为可与适当的模块一起使用。 如果您需要从中引用某些内容,请使用模块语法

我的对话框选项.ts

import {material} from 'angular';

const dialogOptions: material.IDialogOptions = { ... };

export default dialogOptions;

我试图不过度简化,但为了避免写一篇关于这个主题的中篇小说,必须挥手致意,但我相信我希望已经涵盖并传达了关键点。

您正在寻找名称空间而不是模块,所以。

头文件

export namespace vi.input.header {
  export class VIInputDirective {

  }
}

主文件

import { vi } from "./header.ts"; 
var foo = new vi.input.header.VIInputDirective();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM