TypeScript Module 簡單練習

ES6 引進 Module(模組化) 概念,每個 Module 自成獨立 Scope,各 Module 可自由定義變數、型別,要開放外界存取的項目再透過 export 開放。當需要引用其他 Module 時,則必須明確使用 import 匯入才能使用。如此各 Module 可獨立開發維護而不彼此干擾,甚至能實現需要時再動態載入,大幅提升開發及應用彈性。

TypeScript 也支援 Module,我目前的專案沒用到這麼高級的技巧,原本並不打算深入了解,但發現苗頭不對。開源專案如 Angular 2、Vue 早就 Module 滿天飛,不懂 Module 就看不懂範例程式及原始碼,遇到狀況也不知從何查起,感覺自己很廢,好吧,硬著頭皮也要學會。

開始之前推薦幾篇先修知識文章:

先簡單歸納幾則重點:

  1. TypeScript 程式碼只要出現 import 或 export,就會被視為 Module,編譯結果與一般 TypeScript 大不相同。
  2. TypeScript Module 編譯產生的 js 不能單純用 <script src=".."> 載入,需依賴載入機制,載入機制分兩種:
    * 靜態載入: 編譯時將 Module js 檔打包成單一檔案,例如 Node.js 使用的 CommonJS
    * 動態載入: 網頁執行時視需要下載 Module js,例如: AMD 與 RequireJS
  3. 由於瀏覽器對 ES6 支援度不足,故需要額外的 Module 系統輔助, 目前還在百家爭鳴: AMD、CMD、closure、CommonJS、ES6。Visual Studio 的 TypeScript 編譯設定也可指定要用哪一種系統。
  4. 如果不想動用 Node.js,選擇 AMD Module 系統,網頁端使用 ReuqireJS 載入是最簡單的做法。

有了初步認識,來寫一個簡單範例當作練習。

在 ASP.NET MVC 專案 Scripts 目錄開一個 lab 資料夾,放入多個 ts 檔:

Module System 選擇 AMD:

在四個 ts ,我分別練習了不同的 export/import 寫法。首先是 common.ts,class 及 interface 前方加上 export 開放 Message 類別及 IOutput 介面:

//直接在const、function、class、interface前加上export關鍵字
export class Message {
    Time: Date = new Date();
    Text: string;
    constructor(text: string) {
        this.Text = text;
    }
}
 
export interface IOutput {
    Write(msg: Message);
}

console.ts 先從 common.ts 引用 IOutput 及 Message,最後將自己定義的新類別 ConsoleOutput 跟來自 common 的 Message export 出去(註: 如果自己不用純分享,可以寫成 export { Blah } from "./blah")。

import { IOutput, Message } from "./common";
 
class ConsoleOutput implements IOutput {
    Write(msg: Message) {
        console.log(`${msg.Time.toLocaleTimeString()} ${msg.Text}`);
    }
}
 
//各模組可export相同名稱項目
export const Version = "ConsoleOutput 1.0";
 
export { ConsoleOutput, Message };

另一個 dom.ts,import 的做法不太一樣。 * as com 會將 common 所有 export 項目包入名為 com 的變數,使用時需寫成 com.IOutput、com.Message,有點像 Namespace 的觀念。dom.ts 跟 console.ts 都匯出了名為 Version 的 const,由於引用方會用 import 明確宣告,我們不用擔心名稱衝突。最後 export 時加上 default 關鍵字,引用方可以直接寫 import 名稱 from "./dom" 取得 DomOutput。

//取得模組所有匯出項目,包成變數com的成員
import * as com from "./common";
 
class DomOutput implements com.IOutput {
    Write(msg: com.Message) {
        var div = $("<div></div>");
        div.text(`${msg.Time.toLocaleTimeString()} ${msg.Text }`);
        div.appendTo("body");
    }
}
 
//各模組可export相同名稱項目
export const Version = "DomOutput 1.0";
 
//export為預設項目,import時可直接引用
export default DomOutput;

測試程式 main.ts 如下,分別由 dom.ts/console.ts import 取得 DomOutput、ConsoleOutput、Message,餘下的寫法跟一般 TypeScript 無異。

import DomOutput from "./dom";
import { ConsoleOutput, Message } from "./console";
 
var c = new ConsoleOutput();
c.Write(new Message("console test"));
var d = new DomOutput();
d.Write(new Message("dom test"));

編譯出來的 main.js 如下: (注意: TypeScript Module 編譯成的 js 不能以 <script src="scripts/lab/main.js"> 直接載入,會出現 "Mismatched anonymous define() modules" 錯誤,必須改用 require.js require() 函式載入。)

define(["require", "exports", "./dom", "./console"], function (require, exports, dom_1, console_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var c = new console_1.ConsoleOutput();
    c.Write(new console_1.Message("console test"));
    var d = new dom_1.default();
    d.Write(new console_1.Message("dom test"));
});
//# sourceMappingURL=main.js.map

測試網頁如下: (require.js 可使用 NuGet 安裝或從官網下載,接著用 require(["scripts/lab/main"]) 就能順利載入 main.js 並執行之。)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>TypeScript Module Test</title>
</head>
<body>
    <script src="Scripts/jquery-3.2.1.min.js"></script>
    <script src="Scripts/require.js"></script>
    <script>
        require(["scripts/lab/main"]);
    </script>
</body>
</html>

測試 OK,網頁與 Console 都成功印出訊息。而我們也能觀察到 RequireJS 先載入 main.js 再陸續載入 dom.js/console.js/common.js 的過程,代表它能解析相依性自動載入所需模組。

以上就是簡單的 TypeScript Module 演練,謝謝收看。

歡迎推文分享:
Published 10 October 2017 12:53 PM 由 Jeffrey
Filed under:
Views: 5,727



意見

沒有意見

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<October 2017>
SunMonTueWedThuFriSat
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234
 
RSS
創用 CC 授權條款
【廣告】
twMVC

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication