モジュール

JavaScript は、コードのモジュール化を処理するさまざまな方法を長い歴史を持っています。2012 年から存在する TypeScript は、これらの多くの形式に対するサポートを実装してきましたが、時間の経過とともに、コミュニティと JavaScript 仕様は ES モジュール (または ES6 モジュール) と呼ばれる形式に収束しました。import/export構文としてご存知かもしれません。

ES モジュールは 2015 年に JavaScript 仕様に追加され、2020 年までにほとんどの Web ブラウザと JavaScript ランタイムで幅広くサポートされるようになりました。

ハンドブックでは、ES モジュールとその普及した前身である CommonJS の module.exports = 構文の両方を重点的に取り上げます。他のモジュールパターンに関する情報は、モジュール の参照セクションにあります。

JavaScript モジュールの定義方法

TypeScript では、ECMAScript 2015 と同様に、最上位レベルの import または export を含むファイルはモジュールと見なされます。

逆に、最上位レベルの import または export 宣言がないファイルは、その内容がグローバルスコープで使用可能である(したがってモジュールでも使用可能である)スクリプトとして扱われます。

モジュールは、グローバルスコープではなく、独自のスコープ内で実行されます。つまり、モジュールで宣言された変数、関数、クラスなどは、エクスポート形式のいずれかを使用して明示的にエクスポートされない限り、モジュールの外部からは表示されません。逆に、別のモジュールからエクスポートされた変数、関数、クラス、インターフェースなどを利用するには、インポート形式のいずれかを使用してインポートする必要があります。

非モジュール

開始する前に、TypeScript がモジュールと見なすものを理解することが重要です。JavaScript 仕様では、import 宣言、export、または最上位レベルの await を含まない JavaScript ファイルはすべて、スクリプトでありモジュールではないと宣言されています。

スクリプトファイル内では、変数と型は共有グローバルスコープに宣言され、複数の入力ファイルを1つの出力ファイルに結合するoutFileコンパイラオプションを使用するか、HTMLで複数の<script>タグを使用してこれらのファイル(正しい順序で!)を読み込むと想定されます。

現在importexportがないファイルがモジュールとして扱われるようにするには、次の行を追加します。

ts
export {};
Try

これにより、何もエクスポートしないモジュールとしてファイルが変更されます。この構文は、モジュールのターゲットに関係なく機能します。

TypeScript のモジュール

参考資料
Impatient JS (モジュール)
MDN: JavaScript モジュール

TypeScript でモジュールベースのコードを作成する際には、主に 3 つの点を考慮する必要があります。

  • 構文: ものをインポートおよびエクスポートするために使用する構文は何か?
  • モジュール解決: モジュール名(またはパス)とディスク上のファイルの関係は何か?
  • モジュール出力ターゲット: 生成される JavaScript モジュールはどのようなものにする必要があるか?

ES モジュール構文

ファイルは、export default を介してメインエクスポートを宣言できます。

ts
// @filename: hello.ts
export default function helloWorld() {
console.log("Hello, world!");
}
Try

これは次のようにインポートされます。

ts
import helloWorld from "./hello.js";
helloWorld();
Try

デフォルトエクスポートに加えて、default を省略することで、export を介して複数の変数と関数のエクスポートを行うことができます。

ts
// @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;
}
Try

これらは、import 構文を使用して別のファイルで使用できます。

ts
import { pi, phi, absolute } from "./maths.js";
 
console.log(pi);
const absPhi = absolute(phi);
const absPhi: number
Try

追加のインポート構文

インポートは、import {old as new} のような形式を使用して名前を変更できます。

ts
import { pi as π } from "./maths.js";
 
console.log(π);
(alias) var π: number import π
Try

上記の構文を単一のimportに組み合わせて使用できます。

ts
// @filename: maths.ts
export const pi = 3.14;
export default class RandomNumberGenerator {}
 
// @filename: app.ts
import RandomNumberGenerator, { pi as π } from "./maths.js";
 
RandomNumberGenerator;
(alias) class RandomNumberGenerator import RandomNumberGenerator
 
console.log(π);
(alias) const π: 3.14 import π
Try

エクスポートされたすべてのオブジェクトを* as nameを使用して単一のネームスペースにまとめることができます。

ts
// @filename: app.ts
import * as math from "./maths.js";
 
console.log(math.pi);
const positivePhi = math.absolute(math.phi);
const positivePhi: number
Try

import "./file" を使用して、ファイルを取り込み、現在のモジュールに変数を *含めない* ことができます。

ts
// @filename: app.ts
import "./maths.js";
 
console.log("3.14");
Try

この場合、importは何もしません。ただし、maths.ts内のすべてのコードは評価され、他のオブジェクトに影響を与える副作用が発生する可能性があります。

TypeScript 固有の ES モジュール構文

型は、JavaScript の値と同じ構文を使用してエクスポートおよびインポートできます。

ts
// @filename: animal.ts
export type Cat = { breed: string; yearOfBirth: number };
 
export interface Dog {
breeds: string[];
yearOfBirth: number;
}
 
// @filename: app.ts
import { Cat, Dog } from "./animal.js";
type Animals = Cat | Dog;
Try

TypeScript は、型のインポートを宣言するための 2 つの概念を使用して、import 構文を拡張しています。

import type

これは、型のみをインポートできるインポートステートメントです。

ts
// @filename: animal.ts
export type Cat = { breed: string; yearOfBirth: number };
'createCatName' cannot be used as a value because it was imported using 'import type'.1361'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();
Try
インラインtypeインポート

TypeScript 4.5 では、インポートされた参照が型であることを示すために、個々のインポートに type を接頭辞として付けることもできます。

ts
// @filename: app.ts
import { createCatName, type Cat, type Dog } from "./animal.js";
 
export type Animals = Cat | Dog;
const name = createCatName();
Try

これらにより、Babel、swc、esbuild などの TypeScript 以外のトランスパイラは、安全に削除できるインポートを認識できます。

CommonJS の動作を伴う ES モジュール構文

TypeScript には、CommonJS および AMD の require に直接対応する ES モジュール構文があります。ES モジュールを使用したインポートは、ほとんどの場合、これらの環境からの require と同じですが、この構文により、TypeScript ファイルと CommonJS 出力の 1 対 1 の対応が保証されます。

ts
import fs = require("fs");
const code = fs.readFileSync("hello.ts", "utf8");
Try

この構文の詳細については、モジュールリファレンスページをご覧ください。

CommonJS 構文

CommonJS は、npm で配布されるほとんどのモジュールの形式です。上記の ES モジュール構文を使用して記述している場合でも、CommonJS 構文のしくみを簡単に理解しておくと、デバッグが容易になります。

エクスポート

識別子は、module というグローバルオブジェクトの exports プロパティを設定することでエクスポートされます。

ts
function absolute(num: number) {
if (num < 0) return num * -1;
return num;
}
 
module.exports = {
pi: 3.14,
squareTwo: 1.41,
phi: 1.61,
absolute,
};
Try

その後、これらのファイルは require ステートメントを使用してインポートできます。

ts
const maths = require("./maths");
maths.pi;
any
Try

または、JavaScript のデストラクチャリング機能を使用して少し簡素化できます。

ts
const { squareTwo } = require("./maths");
squareTwo;
const squareTwo: any
Try

CommonJS と ES モジュールの相互運用性

デフォルトインポートとモジュールネームスペースオブジェクトインポートの区別に関して、CommonJS と ES モジュールの間には機能の不一致があります。TypeScript には、esModuleInterop を使用して、2 つの異なる制約セット間の摩擦を軽減するためのコンパイラフラグがあります。

TypeScript のモジュール解決オプション

モジュール解決とは、import または require ステートメントから文字列を取得し、その文字列が参照するファイルを確認するプロセスです。

TypeScript には、クラシックとノードの 2 つの解決戦略があります。コンパイラオプション modulecommonjs でない場合のデフォルトであるクラシックは、下位互換性のために含まれています。ノード戦略は、.ts.d.ts の追加チェックを使用して、Node.js が CommonJS モードで動作する方法を複製します。

TypeScript 内のモジュール戦略に影響を与える TSConfig フラグは多数あります。moduleResolutionbaseUrlpathsrootDirs

これらの戦略の動作に関する完全な詳細については、モジュール解決リファレンスページを参照してください。

TypeScript のモジュール出力オプション

出力される JavaScript に影響を与えるオプションが 2 つあります。

  • target は、どの JS 機能をダウングレードする(古い JavaScript ランタイムで実行されるように変換する)か、そのままにするかを決定します。
  • module は、モジュールがお互いにやり取りするために使用するコードを決定します。

使用する target は、TypeScript コードを実行すると予想される JavaScript ランタイムで使用可能な機能によって決まります。それは、サポートする最も古い Web ブラウザ、実行を期待する Node.js の最低バージョン、または Electron など、ランタイムからの独自の制約から生じる可能性があります。

モジュール間のすべての通信はモジュールローダーを介して行われ、コンパイラオプション module は使用するローダーを決定します。ランタイムでは、モジュールローダーは、モジュールを実行する前に、そのモジュールのすべての依存関係の場所を特定し、実行する役割を担います。

例えば、ES モジュール構文を使用した TypeScript ファイルを以下に示します。これには、module のいくつかの異なるオプションが示されています。

ts
import { valueOfPi } from "./constants.js";
 
export const twoPi = valueOfPi * 2;
Try

ES2020

ts
import { valueOfPi } from "./constants.js";
export const twoPi = valueOfPi * 2;
 
Try

CommonJS

ts
"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;
 
Try

UMD

ts
(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;
});
 
Try

ES2020 は、元の index.ts と事実上同じです。

module の TSConfig リファレンスで、利用可能なすべてのオプションとその出力された JavaScript コードを確認できます。

TypeScript 名前空間

TypeScript には、ES モジュール標準より前に存在する namespaces と呼ばれる独自のモジュール形式があります。この構文には、複雑な定義ファイルを作成するための多くの便利な機能があり、DefinitelyTyped でも 依然として積極的に使用されています。非推奨ではありませんが、名前空間のほとんどの機能は ES モジュールに存在するため、JavaScript の方向性に合わせて ES モジュールを使用することをお勧めします。名前空間の詳細については、名前空間リファレンスページを参照してください。

TypeScript ドキュメントはオープンソースプロジェクトです。Pull Request を送信して、これらのページの改善にご協力ください by sending a Pull Request

このページへの貢献者
RCRyan Cavanaugh (52)
OTOrta Therox (7)
MMyo (3)
ABAndrew Branch (2)
HAHossein Ahmadian-Yazdi (2)
18+

最終更新日:2024年3月21日