TypeScript モジュールシステム

モジュールシステムは、現代の TypeScript 開発の基盤です。

TypeScript は ES Module 構文を完全にサポートし、豊富なモジュール解決戦略を提供します。

モジュールシステムにより、コードを再利用可能なユニットに分割し、コードの組織化と再利用を実現できます。


SVG 図解:モジュールのエクスポートとインポート 背景 タイトル モジュールのエクスポート・インポートの流れ user.ts モジュール user.ts export const name = "Alice" export class User { ... } export interface Config { ... 矢印 import main.ts モジュール main.ts import { name, User } from "./user"; import User from "./user" 矢印 use ランタイム 実行結果 JavaScript コードを実行 下半分:エクスポートの種類 エクスポート・インポートの方法 方法1 名前付きエクスポート/インポート 方法2 デフォルトエクスポート/インポート 方法3 再エクスポート 方法4 動的インポート 矢印マーカー

なぜモジュールシステムが必要か

プロジェクトの規模が大きくなるにつれて、コード量はますます増えていきます。

コードを複数のファイルに分散し、モジュールで整理することで、コードの保守性と再利用性を向上させることができます。

モジュールシステムにより、各ファイルが独自のスコープを持ち、グローバル変数の汚染を防ぎます。

概念の説明:モジュールとは、エクスポート文とインポート文を含む TypeScript ファイルです。export で内容をエクスポートし、import で内容をインポートします。


モジュールのエクスポート

export キーワードを使用すると、変数、関数、クラス、インターフェースなどをエクスポートして、他のモジュールで使用できるようにできます。

user.ts モジュール

// 変数のエクスポート
export var name = "Alice";
export const age = 25;

// 関数のエクスポート
export function greet(message: string): string {
    return "Hello, " + message;
}

// クラスのエクスポート
export class User {
    // コンストラクタのパラメータプロパティ
    constructor(public name: string) {}

    // 自己紹介メソッド
    introduce(): string {
        return "I am " + this.name;
    }
}

// インターフェースのエクスポート(インターフェースはコンパイル後に消え、型チェックにのみ使用されます)
export interface Config {
    // ホストの設定
    host: string;
    // ポートの設定
    port: number;
}

// 一括エクスポート:名前を変更してエクスポート
export { name as userName, age as userAge };

注意:インターフェースと型は、コンパイル後の JavaScript では実際のコードを生成しません。これらは TypeScript の型チェックにのみ使用されます。


モジュールのインポート

import キーワードを使用して、他のモジュールからエクスポートされた内容をインポートします。

main.ts でのモジュールのインポート

// 名前付きインポート:モジュールから指定された内容をインポート
import { name, age, greet } from "./user";

// デフォルトインポート:モジュールのデフォルトエクスポートをインポート
import User from "./user";

// すべてインポート:モジュールのすべてのエクスポートを1つのオブジェクトにまとめる
import * as UserModule from "./user";

// 名前を変更してインポート:名前の衝突を回避
import { greet as sayHello } from "./user";

// インポートした内容を使用
console.log(greet("World"));
console.log(sayHello("TypeScript"));

実行結果:

Hello, World
Hello, TypeScript

パスの説明:インポートパスは相対パス(例:./user)または絶対パス(例:@/utils)。


デフォルトエクスポート

各モジュールはデフォルトエクスポートを1つ持つことができます。

デフォルトエクスポートはインポート時に波括弧を使用する必要がなく、任意の名前を付けることができます。

math.ts モジュール

// デフォルトエクスポート:1つのモジュールにはデフォルトエクスポートを1つだけしか持てない
export default function add(a: number, b: number): number {
    return a + b;
}

// 他のエクスポートと組み合わせて使用できる
export function multiply(a: number, b: number): number {
    return a * b;
}

main.ts のインポート

// デフォルトエクスポートのインポート:任意の名前を付けられる
import add from "./math";

// 名前付きエクスポートのインポート:波括弧が必要
import { multiply } from "./math";

console.log("加算: " + add(2, 3));
console.log("乗算: " + multiply(4, 5));

実行結果:

加法: 5
乘法: 20

推奨事項:ユーティリティ関数やクラスなどの主要なエクスポートにはデフォルトエクスポートを使用し、補助関数やインターフェースなどには名前付きエクスポートを使用します。


再エクスポート

再エクスポート(Re-export)は、複数のモジュールの内容を集約したり、あるモジュールのエクスポートを別のモジュールに公開したりするために使用します。

index.ts のモジュール集約

// 他のモジュールから指定された内容を再エクスポート
export { name, age } from "./user";

// デフォルトエクスポートを再エクスポート(名前の変更が必要)
export { default as User } from "./user";

// すべての内容を再エクスポート
export * from "./math";

適用シナリオ:index.ts をエントリファイルとして使用し、サブモジュールの内容を一元的にエクスポートすることで、一括インポートが容易になります。


モジュール解決戦略

TypeScript は、インポートされたモジュールを検索するための複数のモジュール解決戦略を提供します。

tsconfig.json で設定できます。

tsconfig.json の設定

{
    "compilerOptions": {
        // Node 解決戦略
        // Node.js のモジュール解決ルールに従う
        "moduleResolution": "node",

        // クラシック解決戦略
        // TypeScript の初期バージョンで使用されていた戦略
        "moduleResolution": "classic",

        // base URL:ベースパスの設定
        // すべての非相対パスインポートはこのパスに基づいて解決される
        "baseUrl": "./src",

        // パスマッピング:インポートパスにエイリアスを設定
        "paths": {
            // @ で始まるインポートは src ディレクトリにマッピング
            "@/*": ["./*"],
            // @components で始まるインポートは components ディレクトリにマッピング
            "@components/*": ["./components/*"]
        }
    }
}

設定の推奨事項:新規プロジェクトでは Node 解決戦略の使用を推奨します。これは現在最も一般的な方法です。


動的インポート

動的インポート(Dynamic Import)は import() 構文を使用し、実行時に必要に応じてモジュールをロードできます。

これはコード分割や遅延ロードに非常に役立ちます。

例

// 動的インポート - 遅延ロード
// import() は Promise を返す
async function loadMath() {
    // モジュールを動的インポート。この場所まで実行されたときだけロードされる
    var math = await import("./math");

    // math.default はデフォルトエクスポートされた関数
    console.log("動的加算: " + math.default(1, 2));
}

// 遅延ロード関数を呼び出す
loadMath();

// 条件付きインポート:条件に応じて異なるモジュールを動的にロード
async function loadFeature(enable: boolean) {
    if (enable) {
        // 条件が満たされたときだけモジュールをロード
        var feature = await import("./feature");
        feature.run();
    }
}

// 条件に応じてロード
loadFeature(true);

実行結果:

动态加法: 3

パフォーマンス最適化:動的インポートによりコード分割が可能になり、必要なときだけ追加のコードをロードして、初期ロード時間を短縮できます。


注意事項

  • 相対パス:相対パスを使用してローカルモジュールをインポート(./、../)
  • モジュールの拡張子:TypeScript はコンパイル時に拡張子を自動的に処理します
  • デフォルト vs 名前付き:各モジュールに1つのデフォルトエクスポート、複数の名前付きエクスポート
  • esModuleInterop:このオプションを有効にすると、CommonJS モジュールをより簡単にインポートできます

ベストプラクティス:インポートパスを一貫させ、パスエイリアスを使用して長いパスを簡素化し、明確なモジュール組織構造を確立します。


まとめ

モジュールシステムは TypeScript プロジェクト組織化の核です。

  • export:変数、関数、クラス、インターフェースのエクスポート
  • import:エクスポートされた内容のインポート
  • デフォルトエクスポート:各モジュールに1つ、柔軟に使用可能
  • 再エクスポート:モジュールの集約、エントリファイルの作成
  • 動的インポート:遅延ロード、パフォーマンスの最適化
  • モジュール解決:パスエイリアスと解決戦略の設定

推奨事項:モジュール構造を適切に整理し、パスエイリアスを使用してインポートを簡素化し、明確なエクスポート・インポート規約を確立します。

その他の拡張