TypeScript超入門：とりあえず動く環境を作る


# この記事の内容

TypeScriptをコンパイルしてブラウザに表示するまでの環境を作ります。jQueryを使用してテキストを青色にするところがゴールです。

この記事で使用するソースコードはgithubにアップしています。
https://github.com/ringtail003/TypeScript-Starter

## 使用するパッケージ

* npm v2.7.4 (インストール済みとします)
* bower v1.7.2 (インストール済みとします)
* tsc v1.6.2
* gulp v3.9.0
* tsd v0.6.5

# プロジェクトフォルダを作る

以下のようなフォルダ構成を作ります。

```
project/
	src/
		ts/
		js/
	dist/
```

`src`は編集用のソースコードを置くフォルダです。
`dist`はブラウザで表示するルートディレクトリです。

# HTMLを書く

```src/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <script type="text/javascript" src="js/app.js"></script>
    <title>sample</title>
  </head>
  <body>
    <div>TypeScriptの練習</div>
  </body>
</html>
```

# TypeScriptを書く

まずは`console.log()`するだけのサンプルです。

```src/ts/app.ts
namespace module1{
  export class foo{}
}

var foo = new module1.foo();
console.log(foo);
```

# コンパイルしてJavaScriptにする

## tsc

> 最終的にgulpのプラグインを使うことにしたので読み飛ばしてもらってかまいません

TypeScriptはそのままではブラウザが解釈できないためJavaScriptに変換する必要があります。コンパイラの[tsc](https://github.com/Microsoft/TypeScript)を使ってみましょう。

```
$ npm install -g tsc
```

試しにコンパイルしてみます。

```
$ tsc src/ts/app.ts --outDir dist/ts
```

```dist/ts/app.js
var module1;
(function (module1) {
    var foo = (function () {
        function foo() {
        }   
        return foo;
    })();
    module1.foo = foo;
})(module1 || (module1 = {}));
var foo = new module1.foo();
console.log(foo);
```

tscコマンドには[オプション](https://github.com/Microsoft/TypeScript/wiki/Compiler-Options)を渡すことができます。
同じフォルダに`tsconfig.json`が存在すればそこから読み込まれるため毎回同じオプションを指定する必要はありません。

ただ、tscはコンパイラなので多機能ではありません。
`src/ts`を変更したら`dist/ts`に自動でコンパイルしたファイルを展開するところまでやって欲しいので、`gulp`を使うことにしました。

> コンパイルをちょっと試すだけならこちらもおすすめです
[TypeScript Playground](https://www.typescriptlang.org/play/)

## gulp

`gulp`はNode.jsを使ったタスクランナーです。
TypeScriptのコンパイルに限らずさまざまな作業を自動化する事ができます。

```
// package.jsonを作る
// いろいろ聞かれるけど全部Enter
$ npm init

// インストール & package.jsonに保存
$ npm install gulp --save-dev
```

typescriptコンパイラをインストールします。

```
$ npm install gulp-typescript --save-dev
```

タスク定義ファイルを作ります。

```gulpfile.js
var gulp = require('gulp');
var typescript = require('gulp-typescript');

// src/tsをコンパイルしてdist/jsに展開
gulp.task('compile:ts', function(){
  return gulp.src(['src/ts/*.ts'])
    .pipe(typescript())
    .js 
    .pipe(gulp.dest('dist/js/'));
});

// gulpコマンドで実行するデフォルトタスク
gulp.task('default',['compile:ts']);
```

gulpコマンドでタスクが実行されます。

```
$ gulp
```

```dist/ts/app.js
var module1;
(function (module1) {
    var foo = (function () {
        function foo() {
        }   
        return foo;
    })();
    module1.foo = foo;
})(module1 || (module1 = {}));
var foo = new module1.foo();
console.log(foo);
```

## gulpにいろいろやってもらおう

チーム開発しているなら「TypeScriptを編集したらコンパイルしてjsフォルダを更新しておいてね」なんて暗黙のルールを作らずに、コマンド一発でコンパイルやデバッグを開始できるようにしておきたいものですね。それぞれタスクを定義して`gulp`にいろいろやってもらいましょう。

### distフォルダを空っぽに

```
$ npm install del --save-dev
```

```gulpfile.js
var del = require('del');

gulp.task('clean:dist', function(){
  return del.sync(['dist/*']); 
});
```

### HTMLをsrcからdistにコピー

```gulpfile.js
gulp.task('copy:html', function(){
  return gulp.src(['src/*.html']) 
    .pipe(gulp.dest('dist/'));
});
```

### srcフォルダの監視

```gulpfile.js
// ts,htmlが編集されたらタスクを再実行
gulp.task('watch', function(){
  gulp.watch([
    'src/ts/*.ts',
    'src/*.html'
  ], ['compile:ts','copy:html']); 
});
```

### ブラウザ起動

```
$ npm install browser-sync --save-dev
```

```gulpfile.js
var browserSync = require('browser-sync').create();

// filesで指定したファイルが更新された時にリロードしてくれる
gulp.task('server', function(){
  browserSync.init({
    server: {
      baseDir: 'dist'
    },
    files: ['dist/*']
  });
});
```

### gulpコマンドで全部実行するように

```gulpfile.js
gulp.task('default',[
	'clean:dist',
	'compile:ts',
	'copy:html',
	'server',
	'watch'
]);
```

## gulp実行

```
$ gulp

[00:08:00] Using gulpfile ~/project/gulpfile.js
[00:08:00] Starting 'clean:dist'...
[00:08:00] Finished 'clean:dist'...
[00:08:00] Starting 'compile:ts'...

...

[BS] Access URLs:
 ----------------------------------------
       Local: http://localhost:3000
 ...
 
[BS] Serving files from: dist
[BS] Watching files...

```

タスクが次々に実行されてブラウザが起動します。
`app.ts`または`index.html`を編集・保存するとブラウザがリロードします。便利。

## とりあえず完成

ここまででTypeScriptのコードをブラウザで検証する環境が構築できました。次は[jQuery](https://jquery.com/)を使ってテキストを青色にしてみましょう。

## jQueryをインストール

通常のJavaScriptと同じく、jQueryを利用するにはパッケージのインストールと読み込みが必要です。

JavaScriptパッケージの管理には`bower`を利用します。
インストール先は`src/js`にしておいてください。

```.bowerrc
{
	"directory": "src/js/bower_components"
}
```

```
// bower.jsonを作る
// いろいろ聞かれるけど全部Enter
$ bower init

$ bower install jquery --save-dev
```

```src/index.html
<script type="text/javascript" src="js/bower_components/jquery/dist/jquery.js"></script>
```

これも`dist`に展開されるようにしておきます。

```gulpfile.js
// 
gulp.task('copy:bower', function(){
	// アスタリスク2つを指定しないとファイルがコピーされない
	// baseの指定はフォルダ構成を再現する起点
	return gulp.src(
	  	['src/js/bower_components/**'],
  		{ base: 'src/js' }
  	)
    .pipe(gulp.dest('dist/js/'));
});

gulp.task('default',[
	...
	'copy:bower',
	'server',
	'watch'
]);
```

## 色を変えてみる

TypeScriptでjQueryを使ってみましょう。

```src/ts/app.ts
namespace module1 {
	export class foo{
		// JQueryオブジェクトを受け取る
		// Jは大文字
		constructor(private element:JQuery){}
    
		// 色を変更する
		public color(color:string){
			this.element.css('color',color);
		}   
	}
}

$(function(){
  var foo = new module1.foo($('div'));
  foo.color('blue');
});
```

> これからTypeScriptを勉強するところなので、コードの良し悪しは別としてください。

## gulp実行

```
$ gulp

src/ts/app.ts: error: Cannot find name 'jQuery'.
src/ts/app.ts: error: Cannot find name '$'.
```

`jQuery`なんてないと怒られてしまいました。

## TypeScriptにJavaScriptを持ち込む

TypeScriptには型情報などの厳密なルールが存在します。JavaScriptのオブジェクトを持ち込む事は通常できません。

ただしJavaScriptで書かれた豊富なリソースを有効活用するための方法が提供されています。

```
declare var JQuery;
```

`declare`キーワードは指定した機能が存在するという意図をコンパイラに示します。これに加えてjQueryオブジェクトの持つメソッドや引数などの型情報を定義するとコンパイルが通るようになります。

## DefinitelyTyped

自分でjQueryを読み解いてTypeScript用の定義を作るのは至難の技です。

でも心配する事はありません。
世の中に広く使われているJavaScriptパッケージの定義ファイルはすでに用意されているのです。

> **DefinitelyTyped**
http://definitelytyped.org/

[github](https://github.com/DefinitelyTyped/DefinitelyTyped/find/master)を見るとたくさんの定義ファイル(`d.ts`)が並んでいます。これらを使うと自分で定義ファイルを作る事なくJavaScriptパッケージを持ち込む事ができます。

## tsd

DefinitelyTypedの管理ツールです。

> tsd
https://github.com/DefinitelyTyped/tsd

まずインストール

```
$ npm install -g tsd
```

よく使いそうなコマンドは以下の通りです。


### tsd init

`tsd.json` `typings/tsd.d.ts`が作られます。

### tsd query

パッケージを検索します。
[ブラウザで探す](http://definitelytyped.org/tsd/)こともできます。

* `tsd query jquery` モジュール名
* `tsd query jquery/jquery` projectとモジュール名
* `tsd query "*/jquery.*"` フィルタ(Linux/MacOSは"が必要)
* `tsd query jquery -v ">=0.5 <1.0"` バージョン

### tsd install [package]

パッケージをインストールします。

`tsd install [package] -sro`

* `-s` `--save` 設定ファイルに保存
* `-r` `--resolve` 依存を解決
* `-o` `--overwrite` 上書き

### tsd install

初回は`tsd.json`に書かれたものを読み込んでインストールします。2回目以降は上書きインストールされます。

### tsd update -so

最新のパッケージを読み込みします。

### tsd rebundle

`typings/tsd.d.ts`を更新します。その際、存在しないパッケージは削除されます。

## tsdでjQueryをインストール

```
$ tsd install jquery -sro
```

インストールが終了するとパッケージ名と型定義ファイルへの参照が保存されます。

```tsd.json
installed: {
	"jquery/jquery.d.ts": { ... }
```

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

```インストール後のフォルダ
tsd.json
typings/
	tsd.d.ts <-- 定義ファイルの参照
	jquery/
		jquery.d.ts <-- 定義ファイル
```

## app.tsに参照を追加

```
/// <reference path="../../typings/tsd.d.ts" />
```

## gulp実行

```
$ gulp
```

ブラウザに青い文字が表示されました！
ゴールです。

## おわり

TypeScriptを勉強してみようと思っていますが、環境作りだけで1日終わってしまいました。

gulp blacklistなるものを初めて知りました。ブラックリストって怖いネーミングですが、基準を満たさないとプラグインから外れてブラックリスト入りするようです。
https://github.com/gulpjs/plugins/blob/master/src/blackList.json