TypeScript模块导入和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

材料

declare module vi.input {
  ...
}

如果我换import {VIInputDirective} from "./header.ts";main.ts文件,import VIMHeaderDirective = vi.input.header.VIInputDirective;它工作正常,但随后的WebPack上transpile /注射给了我下面的错误:

VM1469:1Uncaught ReferenceError: vi is not defined

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

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

阿鲁安·哈达德(Aluan Haddad)

您没有使用模块。模块具有一个或多个顶层importexport语句。而是使用全局名称空间并创建全局名称空间的子名称空间来组织程序。这称为显示模块模式。它不涉及使用模块。

不幸的是,TypeScript曾经将此模式称为使用内部模块这个术语已经被弃用,使用的module x {}语法(注意缺乏"S为中心x)的强烈反对。该语言引入了同义关键字namespace,以减少混淆。

诸如Webpack,RequireJS和SystemJS之类的JavaScript加载程序和捆绑程序可与模块一起使用,这就是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 = {}));
    

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

  2. import引用namespace成员的作业,例如

    import IDirective = angular.IDirective;
    

    不属于顶级import声明,因此不会导致其包含文件被视为模块。即使将它们放在文件的顶层也是如此。原因是模块系统(无论是AMD,CommonJS,System还是ES2015)使用字符串作为模块说明符,并从此类字符串中导入。可能代表文件路径,URL,解析的简单名称或合成模块ID。

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

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

考虑

services.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不跨文件合并,并且它们具有类似的内部命名方案,这与它们的模块性有关。

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

让我们来看看

headers.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从模块说明符字符串导入的顶级语句,具有讽刺意味的是,main.ts本身就是模块。

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

现在我们来一圈

强文本

declare module vi.input {
    ....
}

如果我从“ ./header.ts”交换导入{VIInputDirective};在main.ts文件中,导入VIMHeaderDirective = vi.input.header.VIInputDirective; 它工作正常,但是然后在transpile / inject上进行webpack给我以下错误:

确实如上所述。import,不靶向模块符字符串,而没有任何其他顶级进口或出口,改变main.ts使得它不再是一个模块。这将导致TypeScript正确进行TypeCheck,使用相互引用的全局变量import = namespace.value是完全合法的,但是它们不是模块,而JavaScript工具(例如Webpack)则在模块上运行。

那么,您将如何在这个勇敢的新世界中编写此应用程序?由于您正在使用模块打包工具Webpack,因此您将一直使用适当的模块来编写它。

主要

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

headers.ts

import {IDirective} from 'angular';

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

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

我的对话选项

import {material} from 'angular';

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

export default dialogOptions;

我尝试过分简化,但为避免就该主题写中篇小说,有必要挥手致意,但我相信我希望能涵盖并传达要点。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章