簡體   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