名前空間(namespace)とモジュール

用語に関する注意:
TypeScript1.5において用語の変更における重要な注意事項があります。

ECMAScript 2015の用語に合わせ、現在では、 内部モジュール("Internal modules")は"namespaces"となり、 外部モジュール("External modules")は単純に"modules"となりました。 具体的には、module X {は、namespace X {と書くのが好ましいと言えます。

イントロダクション

ここでは、TypeScriptの名前空間とモジュールを使用して、あなたのコードを整理する様々な方法を要点を絞って説明します。 また、TypeScriptで名前空間とモジュールを使用した幾つかの高度な命題を乗り越え、 一般的な落とし穴に対処する方法についても説明します。

モジュールについての詳しい説明は、モジュールのドキュメントを参照してください。 名前空間についての詳しい説明は、名前空間のドキュメントを参照してください。

名前空間の使用

名前空間は、グローバルな名前空間内でJavaScriptのオブジェクトに単純に名前が付けられたものです。 これは、名前空間を使用するにあたり、非常にシンプルな構成にしてくれます。 これら名前空間は複数のファイルにまたがり、また--outFileを使用することで連結することが可能です。 名前空間は、HTMLページ内で<script>タグとして含まれる全ての依存性を使用したWebアプリケーション内で、 あなたのコードを構築する良い方法となるでしょう。

ただ、全てのグローバルな名前空間による汚染のように、 コンポーネントの依存の識別が、特に大規模なアプリケーションにおいて難しくなる懸念があります。

モジュールの使用

名前空間のように、モジュールはコードと宣言の両方を含みます。 両者の主な違いは、モジュールはそれらの依存性を宣言することにあります。

また、モジュールはモジュールローダー(CommonJS / Require.jsのような)上で依存性を持つこともします。 これは小規模なJSアプリケーションにとっては最適とは言えませんが、 長期に渡るモジュール管理と保守による利点がある大規模なアプリケーションにとっては重要であると言えます。 モジュールは再利用性の向上、強力な関係性の分離、ツールによるビルドサポートの向上を提供してくれます。

モジュールはNode.jsアプリケーションにおいても覚えておく価値のあるもので、 デフォルトで用意されており、モジュールを使用したコード構築が推奨されています。

ECMAScript 2015からは、モジュールは言語のネイティブの一部として含まれるようになり、 ECMAScript 2015に準拠した全てのコンパイルエンジンにサポートされているはずです。 このため、新しいプロジェクトのモジュールは、このコードの構成化の機構が推奨されます。

名前空間とモジュールの落とし穴

このセクションでは名前空間とモジュールを使用する際に陥りがちな落とし穴と、それらの回避方法について説明します。

/// <reference> によるモジュールの参照

一般的なミスに、import文の使用ではなく、 /// <reference ... />文法を使用してモジュールファイルの参照を試みるとういことが挙げられます。 違いを理解するためには、まずコンパイラがどのようにimportのパスをもとにして、 モジュールの型の情報を見つけ出すのかを理解する必要があります。

(例: import x from "...";import x = require("...");等の...に当たる部分)

コンパイラは適切なパスに従って、.ts.tsxを見つけようとし、次に.d.tsを探します。 もし特定のファイルが見つからなかった場合、コンパイラはambientモジュール宣言を探し、 .d.tsファイル内にある必要な宣言を呼び戻します。

  • myModules.d.ts
    // In a .d.ts file or .ts file that is not a module:
    declare module "SomeModule" {
        export function fn(): string;
    }
    
  • myOtherModule.ts
    /// <reference path="myModules.d.ts" />
    import * as m from "SomeModule";
    

ここでのreferenceタグは、ambientモジュールの宣言を含むファイルを特定してくれます。 このようにして、TypeScriptのサンプルでnode.d.tsファイルが使用されています。

不要な名前空間

もし、プログラム内の名前空間をモジュールへ変更する場合、次のように簡単に行うことが出来ます。

  • shapes.ts
    export namespace Shapes {
        export class Triangle { /* ... */ }
        export class Square { /* ... */ }
    }
    

ここでは特に理由も無く、TriangleSquareが、 最上層のモジュールShapesにラップされています。 これは、あなたのモジュール使用者を混乱させ、苦しめることになるでしょう。

  • shapeConsumer.ts
    import * as shapes from "./shapes";
    let t = new shapes.Shapes.Triangle(); // shapes.Shapes?
    

TypeScriptのモジュールの重要な特徴に、2つの異なるモジュールが同じスコープに名前を提供することが無いということが挙げられます。 何故ならモジュールの使用者が割り当てる名前を何にするか決定するからです。 そのため、名前空間にexportされるシンボルを積極的にラップする必要はありません。

下記は、先程の例を改めた例になります。

  • shapes.ts
    export class Triangle { /* ... */ }
    export class Square { /* ... */ }
    
  • shapeConsumer.ts
    import * as shapes from "./shapes";
    let t = new shapes.Triangle();
    

モジュールにおけるトレードオフ

JavaScriptファイルとモジュールが1対1の関係になるのと同じように、 TypeScriptはモジュールのソースファイルと、それらが出力されるJavaScriptファイルに1対1の関係を持つことになります。

これにより--outFileを使用して、 複数のモジュールのソースファイルを1つのJavaScriptファイルに連結するコンパイラの切り替えが不可能になります。

 Back to top

© https://github.com/Microsoft/TypeScript-Handbook

このページは、ページトップのリンク先のTypeScript-Handbook内のページを翻訳した内容を基に構成されています。 下記の項目を確認し、必要に応じて公式のドキュメントをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。

  • ドキュメントの情報が古い可能性があります。
  • "訳注:"などの断わりを入れた上で、日本人向けの情報やより分かり易くするための追記を行っている事があります。