Typescriptの内部・外部moduleの使い方

##内部モジュール(internal module)

内部モジュールは、共通の関数などをグローバル空間に記載したくない場合などに使用すると便利。
モジュールを外部スコープから参照する際はexportを使用する。

```lang:ts
 
module Util{
	export function testFunc():void{
		alert('testFunc');
		notExportItem()//モジュールの内部からの参照は可能
	}
	
	export class TestClass{
		constructor(){
			alert('TestClass');
		}
	}

	//exportが無いので、外部からの参照ができない
	function notExportItem():void{
		alert('notExportItem');
	}
}

Util.testFunc();
new Util.TestClass();

Util.notExportItem()//エラーとなる
```


###◎モジュールのネストもできる
exportをmoduleに対して使用することで、モジュールのネストが可能です。

```lang:ts
module Util{
	export module Klass{
		export class TestClass{
			constructor(){
				alert('TestClass');
			}
		}	
	}
}

new Util.Klass.TestClass()
```
上記のネストしたモジュールは下記のようにドットで区切って記載することで短縮が可能です。

```lang:ts
module Util.Klass{
	export class TestClass{
		constructor(){
			alert('TestClass');
		}
	}	
}

new Util.Klass.TestClass();
```

ネストが深くなった場合、importを使用してモジュールの参照部分を短くすることができます。

```lang:ts
module Util.Klass{
	export class TestClass{
		constructor(){
			alert('TestClass');
		}
	}	
}

import klass = Util.Klass.TestClass
new klass();

```

###◎モジュールは分割して記載することができる

```lang:ts
module Util{
	export class TestClass{
		constructor(){
			alert('TestClass');
		}
	}	
}

module Util{
	export class TestClass2{
		constructor(){
			alert('TestClass2');
		}
	}	
}

new Util.TestClass();
new Util.TestClass2();

```
上記の書き方だと、後のmoduleの記載で、前のmoduleを上書いてしまうかと思いましたが、
コンパイルされたjsファイルを見ると、上書きされないことがわかりました。

```lang:javascript
//コンパイルされたもの
var Util;
(function (Util) {
    var TestClass = (function () {
        function TestClass() {
            alert('TestClass');
        }
        return TestClass;
    })();
    Util.TestClass = TestClass;
})(Util || (Util = {}));
var Util;
(function (Util) {
    var TestClass2 = (function () {
        function TestClass2() {
            alert('TestClass2');
        }
        return TestClass2;
    })();
    Util.TestClass2 = TestClass2;
})(Util || (Util = {}));
new Util.TestClass();
new Util.TestClass2();

```

##外部モジュール(external module)

外部モジュールはその名の通り、別ファイルとして外部にある機能を利用する仕組みです。
内部モジュールと違い、moduleキーワードは必要なく、exprotキーワード使用することで外部から機能を利用できるようになります。

###◎外部モジュールを使う為の準備

外部モジュールを使用するときは、下記いずれかのAPIを使用する必要がある。
・AMD(Webブラウザ用）
・CommonJS(Node.js用)

AMDを使用する際に<a href="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.20/require.js" target="_blank">RequireJS</a>のようなライブラリを利用する必要がある。

###◎外部モジュールのコードをコンパイルする
・AMD

```lang:tscコマンド
tsc -m amd main.ts
//もしくはtsc -module amd main.ts
```
・CommonJS

```lang:tscコマンド
tsc -m commonjs main.ts
//もしくはtsc -module commonjs main.ts
```
###◎外部モジュールを利用する

ここではフロントエンドで使用する想定でAMD形式でコンパイルし、
RequireJSを使ってロードします。

```lang:index.html
<html>
  <head>
    <script data-main="main" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.20/require.js"></script>
  </head>
  <body>
  </body>
</html>

```

main.tsから、sub.tsのモジュールを読み込みます。
importとrequireキーワードを使用します。
requireには拡張子を除いたファイルパスを指定します。

```lang:main.ts
import sub = require('sub');
sub.func1();

```
外部モジュールは、exportキーワードを使用します。

```lang:sub.ts
export function func1() {
    alert('外部のモジュールだよ')
}

```

moduleを定義することもできます。

```lang:main.ts
import sub = require('sub');
var class1 = new sub.module1.Class1();	
```
```lang:sub.ts
export module module1{
    export class Class1 {
        constructor() {
            alert('ok');
        }
    }
}
```

##一番簡単だと思う外部モジュールの参照方法
外部モジュールは、RequireJSを使ったり一手間かかります。
直接jsファイルを下記のように読み込んで、外部モジュールを参照することもできます。

```lang:index.html
<html>
  <head>
  	<script src="sub.js"></script>
    <script src="main.js"></script>
  </head>
  <body>
  </body>
</html>

```

ts側でも外部のtsファイルの参照をする必要があります。
外部フィアルを参照するには、下記のようなリファレンスパスを使用します。

```lang:main.ts
///<reference path="sub.ts"/>
func1();
```

```lang:sub.ts
function func1() {
    alert('OK')
}
```
htmlにscriptタグを追加するなど、面倒な部分もありますが、
通常の読み込み方に近いので、わかりやすいと思いました。