Modulesjavascript
JavaScript 在處理模塊化代碼方面有着悠久的歷史。 TypeScript 自 2012 年問世以來,已經實現了對許多這些格式的支持,但隨着時間的推移,社區和 JavaScript 規範已經融合到一種稱爲 ES 模塊(或 ES6 模塊)的格式上。 您可能知道它是 import/export 語法。html
ES Modules 於 2015 年添加到 JavaScript 規範中,到 2020 年在大多數 Web 瀏覽器和 JavaScript 運行時中獲得普遍支持。java
爲了重點,手冊將涵蓋 ES 模塊及其流行的前體 CommonJS module.exports = 語法,您能夠在模塊下的參考部分中找到有關其餘模塊模式的信息。typescript
在 TypeScript 中,就像在 ECMAScript 2015 中同樣,任何包含頂級導入或導出的文件都被視爲一個模塊。瀏覽器
相反,沒有任何頂級導入或導出聲明的文件被視爲腳本,其內容在全局範圍內可用(所以也對模塊可用)。app
模塊在它們本身的範圍內執行,而不是在全局範圍內。 這意味着在模塊中聲明的變量、函數、類等在模塊外部不可見,除非它們使用導出形式之一顯式導出。 相反,要使用從不一樣模塊導出的變量、函數、類、接口等,必須使用其中一種導入形式導入。dom
在咱們開始以前,瞭解 TypeScript 將什麼視爲模塊很重要。 JavaScript 規範聲明任何沒有導出或頂級 await 的 JavaScript 文件都應被視爲腳本而不是模塊。模塊化
在腳本文件中,變量和類型被聲明爲在共享全局範圍內,而且假設您將使用 --outFile 編譯器選項將多個輸入文件鏈接到一個輸出文件中,或者在其中使用多個
\<script> 標記 您的 HTML 以加載這些文件(以正確的順序!)。函數
若是您有一個當前沒有任何導入或導出的文件,但您但願被視爲一個模塊,請添加如下行:ui
export {};
這會將文件更改成不導出任何內容的模塊。 不管您的模塊目標如何,此語法都有效。
文件能夠經過 export default 聲明主導出:
// @filename: hello.ts export default function helloWorld() { console.log("Hello, world!"); }
This is then imported via:
import hello from "./hello.js"; hello();
除了默認導出以外,您還能夠經過省略默認導出來導出多個變量和函數:
// @filename: maths.ts export var pi = 3.14; export let squareTwo = 1.41; export const phi = 1.61; export class RandomNumberGenerator {} export function absolute(num: number) { if (num < 0) return num * -1; return num; }
在另外一個文件裏用大括號導入:
import { pi, phi, absolute } from "./maths.js"; console.log(pi); const absPhi = absolute(phi);
還能夠用 import alias 語法:
import { pi as π } from "./maths.js"; console.log(π);
您能夠將全部導出的對象放入一個使用 * 做爲名稱的命名空間中:
// @filename: app.ts import * as math from "./maths.js"; console.log(math.pi); const positivePhi = math.absolute(math.phi);
直接 import 一個文件會有什麼後果?
// @filename: app.ts import "./maths.js"; console.log("3.14");
在這種狀況下,導入什麼都不作。 可是,對 maths.ts 中的全部代碼都進行了評估,這可能會觸發影響其餘對象的反作用。
TypeScript 加強了 import 語法,能夠只 import module 裏的 type 定義。
// @filename: animal.ts export type Cat = { breed: string; yearOfBirth: number }; 'createCatName' cannot be used as a value because it was imported using 'import type'. export type Dog = { breeds: string[]; yearOfBirth: number }; export const createCatName = () => "fluffy"; // @filename: valid.ts import type { Cat, Dog } from "./animal.js"; export type Animals = Cat | Dog; // @filename: app.ts import type { createCatName } from "./animal.js"; const name = createCatName();
模塊解析是從 import 或 require 語句中獲取字符串並肯定該字符串引用哪一個文件的過程。
TypeScript 包括兩種解析策略:Classic 和 Node。 經典,當編譯器標誌模塊不是 commonjs 時的默認值,包含在內是爲了向後兼容。 Node 策略複製了 Node.js 在 CommonJS 模式下的工做方式,並額外檢查了 .ts 和 .d.ts。
有許多 TSConfig 標誌會影響 TypeScript 中的模塊策略:moduleResolution、baseUrl、paths、rootDirs。
有關這些策略如何工做的完整詳細信息,您能夠查閱模塊解決方案。
有兩個選項會影響發出的 JavaScript 輸出:
您使用的目標取決於您但願在其中運行 TypeScript 代碼的 JavaScript 運行時中可用的功能。這多是:您支持的最舊的 Web 瀏覽器,您但願運行或可能來自的最低版本的 Node.js 來自您的運行時的獨特約束——例如 Electron。
模塊之間的全部通訊都經過模塊加載器進行,編譯器標誌模塊肯定使用哪個。在運行時,模塊加載器負責在執行以前定位並執行模塊的全部依賴項。
例如,這是一個使用 ES 模塊語法的 TypeScript 文件,展現了模塊的幾個不一樣選項。
下面是 TypeScript 原始文件:
import { valueOfPi } from "./constants.js"; export const twoPi = valueOfPi * 2;
下面是 ES2020 output:
import { valueOfPi } from "./constants.js"; export const twoPi = valueOfPi * 2;
下面是 CommonJS:
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.twoPi = void 0; const constants_js_1 = require("./constants.js"); exports.twoPi = constants_js_1.valueOfPi * 2;
下面是 UMD:
(function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "./constants.js"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.twoPi = void 0; const constants_js_1 = require("./constants.js"); exports.twoPi = constants_js_1.valueOfPi * 2; });