TypeScript環境の分かりにくいところ

TypeScriptを使っていてどうも分かりにくいなぁというところをなんとなく克服できたのでメモを残しておく。

ちなみに開発環境は、VisualStudio Code 0.10.2(Windows10上以降VSCodeと略記する) + tsc-1.6.2。最初は本家のVisualStudio上でやろうとしていたのだけど、いろいろ試しているうちVSCode + gulpが手に馴染んで来たので今はこの組み合わせで、tsc駆動にはgulp-typescriptを使っている。しかし、VSCodeって名前以外VisualStudioと無関係なのね。Electron製だし・・・

# 情報はハンドブックを参照するべし
分からないことがあったら、グーグル先生に聞く前に

- http://www.typescriptlang.org/Handbook

を見る。一次情報を参照した方が身のためだ。
実際、英語だけどまとまっているので目を通すとよいのではないか。
(まだ、全部は読んでない)

# 内部モジュールと外部モジュール
ちょっとグーグル先生に尋ねてみれば日本語の記事がいくつか出てくるのだけれど、
ハンドブックに以下の記述がある。

> External modules are used in two cases: node.js and require.js. 

これを見てどういうことかわかった。

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

モジュールと使うコードが同じファイルにある基本形。

```ts:app.ts
module Hoge {
    export var value='hoge';
}

console.log(Hoge.value);
```

モジュールと使うコードが違うファイルにある。
[Splitting Across Files](http://www.typescriptlang.org/Handbook#modules-splitting-across-files)

```ts:hoge.ts
module Hoge {
    export var value='hoge';
}
```

```ts:app.ts
/// <reference path="hoge.ts" />
console.log(Hoge.value);
```

かつ

```html
<script src="hoge.js" type="text/javascript" />
<script src="app.js" type="text/javascript" />
```

であると書いてある。
内部モジュールはブラウザで個々のjsがscriptタグで読み込まれるケースが想定されている。


JQueryを使う場合がこれにあたり、

```ts:client.ts
/// <reference path="./typings/jquery/jquery.d.ts" />

function hello(selector: JQuery)
{
    console.log(selector);
}

$(()=>{

    hello($('body'));

});
```

こんな感じで記述する。
importする側はどこか外側のscriptタグで必要な要素は読み込まれていると見なすことになる。
JQuery等の型はグローバルなネームスペース？に直接展開される。

ちなみに定義は、

```typescript:jquery.d.ts
interface JQuery {
    // 省略
}

declare module "jquery" {
    export = $;
}
```

という感じだった。


## 外部モジュール(external module)
external moduleは、node.js側で使われるもので

```typescript:app.ts
import http = require('http');
import express = require('express');
```

というような感じでimportする。
型は下記のようにネームスペースの中に展開される。

```typescript
function logResponse(response: express.Response)
{
    console.log(response);
}
```

定義側は、

```typescript:typings/node/node.d.ts
declare module "http" {
    // 省略
}
```

という感じでinternal moduleと同じだった。internalとexternalはimportの仕方で変わるのか。

## コンパイル通らなかった

```ts:app.ts
/// <reference path="./typings/tsd.d.ts" />
import http = require('http');
import express = require('express');
```

とする必要があった。referenceはインテリセンスには要らないが、
tscには要るらしい。分かりにくい。

# gulpfile.coffeeとVSCodeが同じtsconfig.jsonを見るようにする

```coffee
# gulpfile.cofee
config={
    tsconfig: './tsconfig.json',
    dst_js: './build/js'
}
gulp.task 'ts', ->
  tsconfig = require(config.tsconfig)  
  gulp.src config.src_ts
    .pipe $.typescript(tsconfig.compilerOptions).js
    .pipe gulp.dest config.dst_js
```

# VSCodeの癖
インテリセンスが効いたり効かなかったりするというか、
モジュールの探索がよくわからん。

* tsconfig.jsonのfilesやexclude設定を見ている、ような気がする。fileGlobsはどうなのか？
* tsconfig.jsonを変更したときはVSCodeを再起動した方がいい、ような気がする。
* node.jsのグローバルのrequireとかconsole, processの定義はtypings/node/node.d.tsから拾ってくれる。tsdでいれるべし
* browserのグローバルのdocumentとかalertの定義はnode_modules/typescript/lib.es6.d.tsから拾ってくれてた。npmでいれるべし

今、記事を書きながら試した感じだとfiles等は空でもtypingsやsrc/typingsを
探索してくれた。
ちょっと前のバージョンはそんなことは無かったような気もするのだが・・・。

# まとめ
TypeScriptでは、ブラウザとサーバーでモジュールの作法が違う。
ブラウザは内部モジュール(internal module)でreferenceコメントで参照する。
サーバーは外部モジュール(express module)でimport構文で参照しつつreferenceコメントも書いておく。
いまいち確信が持てない・・・