ES6 模組
TypeScript 1.5 支援 ECMAScript 6 (ES6) 模組。ES6 模組實際上就是具有新語法的 TypeScript 外部模組:ES6 模組是獨立載入的原始檔,可以匯入其他模組並提供多個可供外部訪問的匯出內容。ES6 模組具有若干新的匯出和匯入宣告。建議將 TypeScript 庫和應用程式更新為使用新語法,但這並非強制要求。新的 ES6 模組語法可以與 TypeScript 原有的內部和外部模組結構共存,並且這些結構可以隨意混合使用。
匯出宣告
除了現有的 TypeScript 支援透過 export 修飾宣告外,模組成員還可以使用單獨的匯出宣告進行匯出,並可選擇使用 as 子句為匯出指定不同的名稱。
tsinterface Stream { ... }function writeToStream(stream: Stream, data: string) { ... }export { Stream, writeToStream as write }; // writeToStream exported as write
匯入宣告也可以選擇使用 as 子句為匯入指定不同的本地名稱。例如
tsimport { read, write, standardOutput as stdout } from "./inout";var s = read(stdout);write(stdout, s);
作為單獨匯入的替代方案,可以使用名稱空間匯入來匯入整個模組
tsimport * as io from "./inout";var s = io.read(io.standardOutput);io.write(io.standardOutput, s);
重新匯出
使用 from 子句,模組可以將給定模組的匯出複製到當前模組中,而無需引入本地名稱。
tsexport { read, write, standardOutput as stdout } from "./inout";
export * 可用於重新匯出另一個模組的所有匯出。這對於建立聚合了其他多個模組匯出的模組非常有用。
tsexport function transform(s: string): string { ... }export * from "./mod1";export * from "./mod2";
預設匯出
預設匯出(export default)宣告指定了一個表示式,該表示式將成為模組的預設匯出
tsexport default class Greeter {sayHello() {console.log("Greetings!");}}
反過來,它可以使用預設匯入進行匯入
tsimport Greeter from "./greeter";var g = new Greeter();g.sayHello();
裸匯入
“裸匯入”可用於僅為了副作用而匯入模組。
tsimport "./polyfills";
有關模組的更多資訊,請參閱 ES6 模組支援規範。
宣告和賦值中的解構
TypeScript 1.5 增加了對 ES6 解構宣告和賦值的支援。
宣告
解構宣告引入一個或多個命名變數,並使用從物件屬性或陣列元素中提取的值對其進行初始化。
例如,下面的示例聲明瞭變數 x、y 和 z,並分別將它們初始化為 getSomeObject().x、getSomeObject().y 和 getSomeObject().z
tsvar { x, y, z } = getSomeObject();
解構宣告也適用於從陣列中提取值
tsvar [x, y, z = 10] = getSomeArray();
同樣,解構也可用於函式引數宣告
tsfunction drawText({ text = "", location: [x, y] = [0, 0], bold = false }) {// Draw text}// Call drawText with an object literalvar item = { text: "someText", location: [1, 2, 3], style: "italics" };drawText(item);
賦值
解構模式也可以用於常規賦值表示式。例如,交換兩個變數可以寫成一個解構賦值
tsvar x = 1;var y = 2;[x, y] = [y, x];
namespace 關鍵字
TypeScript 使用 module 關鍵字來定義“內部模組”和“外部模組”;這對於 TypeScript 新手來說造成了一些困惑。“內部模組”更接近大多數人所說的名稱空間;同樣,JS 中的“外部模組”現在實際上就是指模組。
注意:之前定義內部模組的語法仍然受支援。
之前:
tsmodule Math {export function add(x, y) { ... }}
之後:
tsnamespace Math {export function add(x, y) { ... }}
let 和 const 支援
在針對 ES3 和 ES5 時,現在支援 ES6 的 let 和 const 宣告。
Const
tsconst MAX = 100;++MAX; // Error: The operand of an increment or decrement// operator cannot be a constant.
塊級作用域
tsif (true) {let a = 4;// use a} else {let a = "string";// use a}alert(a); // Error: a is not defined in this scope.
for..of 支援
TypeScript 1.5 增加了對 ES6 for..of 迴圈的支援,既適用於 ES3/ES5 的陣列,也在針對 ES6 時提供了對迭代器介面的完全支援。
示例
當針對這些版本時,TypeScript 編譯器會將陣列的 for..of 轉換成符合習慣的 ES3/ES5 JavaScript 程式碼
tsfor (var v of expr) {}
將被編譯為
jsfor (var _i = 0, _a = expr; _i < _a.length; _i++) {var v = _a[_i];}
裝飾器
TypeScript 裝飾器基於 ES7 裝飾器提案。
裝飾器是
- 一個表示式
- 它求值為一個函式
- 該函式接收目標、名稱和屬性描述符作為引數
- 並可選擇返回一個要安裝在目標物件上的屬性描述符
有關更多資訊,請參閱 裝飾器 提案。
示例
裝飾器 readonly 和 enumerable(false) 將在屬性 method 安裝到類 C 之前應用於該屬性。這允許裝飾器更改實現,在本例中,增強描述符使其 writable 為 false,enumerable 為 false。
tsclass C {@readonly@enumerable(false)method() { ... }}function readonly(target, key, descriptor) {descriptor.writable = false;}function enumerable(value) {return function (target, key, descriptor) {descriptor.enumerable = value;};}
計算屬性
使用動態屬性初始化物件可能會有些麻煩。以以下示例為例
tstype NeighborMap = { [name: string]: Node };type Node = { name: string; neighbors: NeighborMap };function makeNode(name: string, initialNeighbor: Node): Node {var neighbors: NeighborMap = {};neighbors[initialNeighbor.name] = initialNeighbor;return { name: name, neighbors: neighbors };}
在這裡,我們需要建立一個變數來儲存 neighbor-map,以便我們可以初始化它。在 TypeScript 1.5 中,我們可以讓編譯器來處理這些繁重的工作
tsfunction makeNode(name: string, initialNeighbor: Node): Node {return {name: name,neighbors: {[initialNeighbor.name]: initialNeighbor,},};}
支援 UMD 和 System 模組輸出
除了 AMD 和 CommonJS 模組載入器外,TypeScript 現在還支援輸出 UMD (通用模組定義) 和 System 模組格式。
用法:
tsc —module umd
和
tsc —module system
字串中的 Unicode 碼點轉義
ES6 引入了轉義,允許使用者僅使用單個轉義符來表示 Unicode 碼點。
例如,考慮需要轉義包含字元 ’𠮷‘ 的字串。在 UTF-16/UCS2 中,’𠮷’ 表示為代理對,這意味著它使用一對值分別為 0xD842 和 0xDFB7 的 16 位程式碼單元進行編碼。以前,這意味著你必須將碼點轉義為 "\uD842\uDFB7"。這樣做的一個主要缺點是很難將兩個獨立的字元與代理對區分開來。
使用 ES6 的碼點轉義,你可以透過單個轉義符在字串和模板字串中清晰地表示該字元:"\u{20bb7}"。TypeScript 會在 ES3/ES5 中將其輸出為 "\uD842\uDFB7"。
ES3/ES5 中的標記模板字串
在 TypeScript 1.4 中,我們為所有目標添加了模板字串支援,併為 ES6 添加了標記模板支援。感謝 @ivogabe 所做的巨大工作,我們彌補了 ES3 和 ES5 中標記模板的缺失。
當針對 ES3/ES5 時,以下程式碼
tsfunction oddRawStrings(strs: TemplateStringsArray, n1, n2) {return strs.raw.filter((raw, index) => index % 2 === 1);}oddRawStrings`Hello \n${123} \t ${456}\n world`;
將被編譯為
jsfunction oddRawStrings(strs, n1, n2) {return strs.raw.filter(function (raw, index) {return index % 2 === 1;});}(_a = ["Hello \n", " \t ", "\n world"]),(_a.raw = ["Hello \\n", " \\t ", "\\n world"]),oddRawStrings(_a, 123, 456);var _a;
AMD 依賴的可選名稱
/// <amd-dependency path="x" /> 會通知編譯器有一個非 TS 模組依賴,需要將其注入到生成的模組的 require 呼叫中;但是,之前在 TS 程式碼中無法使用此模組。
新的 amd-dependency name 屬性允許為 amd-dependency 傳遞一個可選名稱
ts/// <amd-dependency path="legacy/moduleA" name="moduleA"/>declare var moduleA: MyType;moduleA.callStuff();
生成的 JS 程式碼
jsdefine(["require", "exports", "legacy/moduleA"], function (require,exports,moduleA) {moduleA.callStuff();});
透過 tsconfig.json 實現專案支援
在目錄中新增 tsconfig.json 檔案表示該目錄是 TypeScript 專案的根目錄。tsconfig.json 檔案指定了編譯專案所需的根檔案和編譯器選項。專案可以透過以下方式之一進行編譯
- 在呼叫 tsc 時不帶輸入檔案,在這種情況下,編譯器會從當前目錄開始並沿著父目錄鏈向上搜尋 tsconfig.json 檔案。
- 在呼叫 tsc 時不帶輸入檔案,並使用 -project(或簡寫為 -p)命令列選項指定包含 tsconfig.json 檔案的目錄路徑。
示例
{"": {"": "commonjs","": true,"": true}}
更多詳情,請參閱 tsconfig.json wiki 頁面。
--rootDir 命令列選項
outDir 選項會在輸出中複製輸入目錄的層級結構。編譯器將所有輸入檔案的最長公共路徑計算為輸入檔案的根目錄;然後利用它在輸出中複製其所有子結構。
有時這並不理想,例如輸入 FolderA\FolderB\1.ts 和 FolderA\FolderB\2.ts 將導致輸出結構映象 FolderA\FolderB\。現在如果向輸入中添加了一個新檔案 FolderA\3.ts,輸出結構將彈出以映象 FolderA\。
rootDir 指定了要在輸出中映象的輸入目錄,而不是對其進行計算。
--noEmitHelpers 命令列選項
TypeScript 編譯器在需要時會輸出一些輔助函式,如 __extends。這些輔助函式會出現在它們被引用的每個檔案中。如果你想將所有輔助函式整合到一個地方,或者覆蓋預設行為,可以使用 noEmitHelpers 來指示編譯器不要輸出它們。
--newLine 命令列選項
預設情況下,輸出換行符在 Windows 系統上為 \r\n,在 *nix 系統上為 \n。newLine 命令列標誌允許覆蓋此行為,並指定在生成的輸出檔案中使用的換行符。
--inlineSourceMap 和 inlineSources 命令列選項
inlineSourceMap 會導致 source map 檔案以內聯方式寫入生成的 .js 檔案中,而不是作為獨立的 .js.map 檔案。 inlineSources 允許將原始檔 .ts 檔案也以內聯方式寫入 .js 檔案中。