TypeScript超入門(3)：モジュール


* [TypeScript超入門：とりあえず動く環境を作る](http://qiita.com/ringtail003/items/40c7e74b72ce5a371c46)
* [TypeScript超入門(2)：構文を理解する](http://qiita.com/ringtail003/items/7ccf992f18b768e0e633)
の続きです。

とりあえず動く環境があり、構文も何となく理解したものの、複数ファイルに書いたとたんに動いてくれませんでした。今回はモジュールについての理解とまとめです。

# この記事を書いた環境

`tsc v1.6.2`でコンパイル・検証しています

# 参考にしたサイト

> [TypeScriptで複数ファイル構成する2つの方法](http://teppeis.hatenablog.com/entry/2014/05/typescript-external-modules)
モジュール/Node.js/AMDなどを横断的に説明しているので分かりやすいです。

## グローバルモジュール

**reference**で参照する方法。`d.ts`を取り込むだけではなくて本来は外部ファイルを参照するための方法らしい。

```ts:app.ts
function f():string {
	return 'test';
}
```

```ts:app2.ts
/// <reference path="./app.ts" />
f();
```

```
$ tsc app2.js --outFile out.js
```

**コンパイル結果**

```js
function f() {
	return 'f';
}
/// <reference path="./app.ts" />
f();
```

* 関数`f`がグローバル空間に展開される
* このやり方は`jQuery`などの汎用的な外部ライブラリに使われる

## 内部モジュール

**module**を定義する方法。
**namespace**でも可(ES6の`module`と区別するためにこちらが推奨らしい)

```ts:app.ts
module app {
	export function f(): string {
		return 'f';
	}
}
```

```ts:app2.ts
/// <reference path="./app.ts" />

module app2 {
	app.f();
}
```

```
$ tsc app2.js --outFile out.js
```

**コンパイル結果**

```js
var app;
(function (app) {
    function f() {
        return 'f';
    }   
    app.f = f;
})(app || (app = {}));
/// <reference path="./app.ts" />
var app2;
(function (app2) {
    app.f();
})(app2 || (app2 = {}));
```

* 関数`f`が名前空間`app`に展開される
* グローバル空間を汚染しない

## 外部モジュール

**簡単にまとめ**

外部モジュールは機能を複数のファイルに分割し、それぞれをモジュールとして参照する仕組みの事。JavaScriptにはこの仕組みがないため、`CommonJS`というAPI仕様が策定され、それをサポートする環境([Node.js](http://nodejs.org/))で使われるようになった。

ブラウザでモジュールが動作する仕組みは`AMD`という別の仕様に切り離されている。[WebPack](http://webpack.github.io/docs/)や[Browserfy](http://browserify.org/)などを使ってブラウザが解釈可能なJavaScriptに変換するか、[RequireJS](http://requirejs.org/)を使って実行時に変換する方法がある。

## 外部モジュール(CommonJS)

**export/import/require**で参照を定義する。

```ts:app.ts
export function f(): string {
	return 'f';
}
```

```ts:app2.ts
import app = require('./app');
app.f();
```

`commonjs`形式でコンパイル

```
$ tsc app2.ts --module commonjs --outDir dist
```

**コンパイル結果**

```js:app.js
function f() {
	return 'f';
}
exports.f = f;
```

```js:app2.js
var app = require('./app');
app.f();
```

* `exports/require`に置き換わる
* Node.jsで使用できる

## 外部モジュール(AMD)

**export/import/require**で参照を定義する。

```ts:app.ts
export function f(): string {
	return 'f';
}
```

```ts:app2.ts
import app = require('./app');
app.f();
```

`amd`形式でコンパイル

```
$ tsc app2.ts --module amd --outDir dist
```

**コンパイル結果**

```js:app.js
define(["require", "exports"], function (require, exports) {
    function f() {
        return 'f';
    }   
    exports.f = f;
});
```

```js:app2.js
define(["require", "exports", './app'], function (require, exports, app) {
    app.f();
});
```

* `exports/define`に置き換わる

## RequireJSを使って読み込んでみる

```html
<html>
	<head>
		<script type="text/javascript" data-main="js/app.js" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js"></script>
	</head>
</html>
```

```ts:app.ts
import utils = require('./utils');

console.log(utils.f());
```

```ts:utils.ts
export function f(){
	return 'test';
}
```

```
$ tsc app.ts --module amd --outDir dist
```

* `exports/define`がrequireJSによって解決されブラウザで動作するようになる

## ES6 module

TypeScriptがサポートするES6 moduleの書き方もできる。

```ts:utils.ts
export default function (){
	return 'f';
}
export function f1(){
	return 'f1';
}
```

`utils`を別名でインポートする

```ts:app.ts
import * as u from './utils';
u.default();
u.f1();
```

`f1()`をインポートする

```ts:app.ts
import {f1} from './utils';
f1();
```