前回はなぜTypeScriptか?という話を書きました。今回はTypeScriptを使うとして、どういう環境を作れば気持ちよく開発できるかについて解説します。
本稿に出てくるサンプルをまとめたリポジトリを随時メンテしております。時期によっては、本記事の内容に沿わない(より磨かれた)状態になっているかもしれません。
TypeScriptの開発環境が指すものは2つあります。IDEやエディタといった、本当に開発を行うための環境と、初期設定を行ったりリリースビルドを作ったりするためのタスクランナーの二種類です。
本記事ではお勧めの構成として、Visual Studio Code+grunt+dtsmを用いていきます。別構成として、Atomとgulp、tsdについても言及します。いずれの構成でも、Mac OS X、Windows、Linuxといった主要なプラットフォームで同じように動かすことができます。
TypeScriptのインストール
Node.js+npmはすでに導入してある前提で進めます。$ npm install -g typescript
か、それで失敗する環境の場合は$ sudo npm install -g typescript
を行ってください。現時点(2015年10月9日)では、TypeScript 1.6.2がインストールされます。TypeScriptコンパイラ(tscコマンド)のバージョンを確認するには、$ tsc -v
を実行します。
tsconfig.json
tsconfig.jsonはTypeScript 1.5.3から登場した要素です。TypeScriptコードをコンパイルする際に、コンパイルオプションとコンパイル対象のtsコードの指定をひとまとめにした設定ファイルです。
今までTypeScriptのコードをJavaScriptにコンパイルするには、tscコマンドにコンパイルオプションや.tsファイルのパスを与えてコンパイルしていました。この方法の問題点は、どういうオプションを渡せばプロジェクトを正しくコンパイルすることができるかわからないということです。また、ファイル同士の依存関係の記述方法も問題でした。reference commentと呼ばれる、TypeScriptコード同士の依存関係をコード中に書く方式が一番最初にありました。これだと依存関係をいちいち記述するのが大変面倒くさく、コンパイル時のエントリーポイントとなるコードを間違えると生成されるコードが変わり、その影響で依存順次第で実行時エラーになる…というパターンもありました。
後述するgruntやgulpなどのタスクランナーを使えば、プロジェクトメンバーやコントリビュータとの手法の共有はできるようになります。依存関係についても毎回同じ方法でコンパイルするようになるため、コンパイル開始のエントリポイントとなる1つのファイルからtree状に依存関係を記述していく方法で楽をすることができるようになりました。しかし、IDEやエディタからはGruntfile.jsやgulpfile.jsの設定値は活用することができないため、入力補完やエラー報告の正確さに不満がありました。
これら、コンパイル方法の指定・TypeScriptコード同士の依存関係を解決できるのが、ここで紹介するtsconfig.jsonです。tsconfig.jsonはTypeScriptコンパイラ、人間、エディタの3者が理解することができる、便利なコンパイル方法の記述手段なのです。
Microsoft先生は最近OSSに対する貢献をどんどん強化してきていますが、まだNode.js+npmやエディタ周りの文化に対する理解が薄いです。そのためtsconfig.jsonについて、めちゃめちゃ使いにくい仕様が生まれています。たとえば、TypeScript 1.5.3ではfilesプロパティにコンパイル対象とするファイルの一覧を1つ1つ書かねばならず、大変面倒くさいです。TypeScript 1.6.0-betaではexcludeプロパティに除外するファイルやフォルダを指定できますが、filesプロパティとの併用はできませんし一部除外解除の設定もできません。basarat氏がatom-typescriptで実装している、filesGlobsプロパティのように、ワイルドカードや除外ルールの組み合わせで順番や対象をコントロールできる方式のほうが優れていると思うのですけどね。
とはいえ、tsconfig.jsonを使いこなすと便利です。今後はtsconfig.jsonがあるとTypeScriptでコードを書くにあたりいろいろな恩恵が得られると思いますので、本連載ではtsconfig.jsonを中心とした環境づくりを紹介していきます。
では、実際にtsconfig.jsonを使ってみましょう。tsconfig.jsonは特別な理由がない限り、プロジェクトルートに1つ置いて使います。TypeScript 1.6.0-beta以降では、--init
オプションが使えるため、tsc --init
を実行するとリスト1が得られます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "compilerOptions": { "module": "commonjs", "target": "es3", "noImplicitAny": false, "outDir": "built", "rootDir": ".", "sourceMap": false }, "exclude": [ "node_modules" ] } |
特にこだわりがなければ、このまま使いはじめてもよいでしょう。しかし、excludeプロパティだけでの運用は細やかなコントロールができないため難しいでしょう。
本連載では、リスト2の構成を使います。filesGlobプロパティはtscコマンドやVSCがサポートしているプロパティではありません。atom-typescriptやgrunt-tsconfig-update、gulp-tsconfig-updateによるfilesプロパティへの展開などのフローを組み合わせていくことでフォローしていきます。リスト2の設定であれば、libディレクトリ配下に置いたコード、testディレクトリ配下に置いたコード、typings配下に置いた型定義ファイルがコンパイル時に自動的に処理されるようになるでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
{ "compilerOptions": { "module": "commonjs", "target": "es5", "noImplicitAny": true, "experimentalDecorators": false, "sourceMap": true, "declaration": false, "noEmitOnError": true }, "filesGlob": [ "./lib/**/*.ts", "./lib/**/*.tsx", "!./lib/**/*.d.ts", "./test/**/*.ts", "./test/**/*.tsx", "!./test/**/*.d.ts", "./typings/**/*.ts", "./node_modules/typescript/lib/lib.es6.d.ts" ], "files": [ ] } |
tsconfig.jsonを用意したら、後は$ tsc --project ./
または$ tsc -p ./
とすることでコンパイルを行うことができます。直接tsconfig.jsonを指定するのではなく、tsconfig.jsonがあるディレクトリを指定するのがポイントです。
設定可能な項目については公式wikiのtsconfig.jsonとコンパイラオプションの項目を参照してください。
型定義ファイルマネージャ
TypeScriptでコードを書くにあたり、もっともつらく、面倒なことを示しておきます。
TypeScriptはJavaScriptのsupersetであるので、既存のjQueryやAngularJSなどのJavaScript製ライブラリも利用することができます。しかしながら、JavaScriptで書かれているということは、ソースコードの字面上からなんというプロパティがあって、なんという関数があって、変数の型が何か、なんて全然わからないわけです。そのため、既存ライブラリをTypeScriptで使おうと思ったら、人間が型の情報を手書きしてライブラリの全体像をTypeScriptコンパイラに教えてやらねばならないのです。
型情報を記述したファイルを型定義ファイルと呼んでいます。有名どころのライブラリであれば、DefinitelyTypedというリポジトリで型定義ファイルを見つけることができます。たとえば、jQueryやAngularJS、Node.jsの型定義ファイルなどはすでに成熟したものが存在しています。これら有名どころのライブラリはただ単にダウンロードしてきて使えばよいですが、マイナーなライブラリや非公開の社内ライブラリの場合は、自分で型定義ファイルを書き起こさなければなりません。
とはいえ、たとえばjQueryであれば最低限declare var $: any;
という型定義を書いておけば、コンパイルを通すことはできます。充実した型定義は開発を加速しますが、最初のうちはざっくりした定義を与えておき、後から必要に応じて徐々に拡充していけば十分です。その過程でバグもより多く見つかるようになっていくことでしょう。
これら、型定義ファイルを上手に管理するためのツールも記事内で紹介します。
dtsm
手前味噌ですが、筆者(わかめ)が製作している型定義ファイルマネージャです。詳しい紹介は(ちょっと古いですが)Qiitaの記事を参照していただければと思います。
TypeScript界でデファクトのtsdに対する優位点として、型定義ファイルを集めたリポジトリをまるごとcloneしてくるため、一度cloneした後は高速に動作し、オフラインでの検索やインストールが可能です。また、npmやbowerといった広く使われているパッケージマネージャと使い方をなるべく似せてあるため、学習コストが低くすみます。
npm install -g dtsm
でインストールできます。
一番シンプルな使い方は、dtsm search ui-router
などで検索し、dtsm install angular-ui-router/angular-ui-router.d.ts
やdtsm install angular-ui-router
で型定義ファイルを取得します。取得した型定義ファイルはtypingsディレクトリに格納されます。
型定義ファイルの更新などに簡単に対応できるようにするには、dtsm init
でdtsm.jsonを作成し、dtsm install --save angular-ui-router
でdtsm.jsonに設定を書き込みます。更新はdtsm update --save
で行うことができます。
企業内に閉じたgitリポジトリ上で管理されている型定義ファイルなども参照させることができます。
tsd
TypeScript界でデファクトで使われている型定義ファイルマネージャです。GitHubのAPIを叩いて型定義ファイルを取得するため、たまに動作が遅い時があったり、企業などで同一IPアドレスからの利用が多くなるとRate Limitがかかってしまい、Tokenの取得や設定が必要になったりする場合があります。
npm install -g tsd
でインストールできます。
一番シンプルな使い方は、tsd query "*ui-router"
などで検索し、tsd install angular-ui-router
で型定義ファイルを取得します。取得した型定義ファイルはtypingsディレクトリに格納されます。
型定義ファイルの更新などに簡単に対応できるようにするには、tsd init
でtsd.jsonを作成し、tsd install angular-ui-router --save
でtsd.jsonに設定を書き込みます。更新はtsd reinstall --overwrite --save
で行うことができます。
ビルドタスクとタスクランナー
TypeScriptプロジェクトを運用するために必要なタスクの紹介と、gruntとgulpの2つのタスクランナーについて取り上げていきます。筆者は普段gruntを使っているため、gulp周りについて改善できそうな箇所があったらサンプルリポジトリに対してpull requestなどいただけたらと思います。
最低限必要なタスクはたった2つだけです。
1つ目は、tsconfig.jsonのfilesプロパティを更新するためのgrunt-tsconfig-updateとgulp-tsconfig-updateです。grunt版は僕が、gulp版はlacoくんが作ってくれました。
2つ目は、tsc -p ./
相当の操作をしてくれるgrunt-ts(5.0.0-beta.4以上)か、gulp-shellです。tscコンパイラに指定する内容自体がtsconfig.jsonによって大幅に簡略化されたため、grunt-tsもgrunt-shellに置き換えてしまってよいかもしれません。
これに、いくつかのタスクをオプションで追加してもよいでしょう。候補を挙げておきます。
よくないスタイルのTypeScriptコードを検出し教えてくれるtslintと、それを各タスクランナー用に切り出したgrunt-tslintとgulp-tslint。
TypeScriptコードにフォーマッタを適用しきれいにしてくれるtypescript-formatterと、それを各タスクランナー用に切り出したgrunt-typescript-formatterとgulp-tsfmt。
TypeScriptコードからドキュメントを生成してくれるtypedocと、それを各タスクランナー用に切り出したgrunt-typedocとgulp-typedoc。
dtsm, tsdとgrunt-dtsm、grunt-tsd、gulp-tsd。
大部分がgrunt-shellやgulp-shellからの呼び出しでもよいような気がしますね…。
エディタ
最後にエディタです。記事で紹介するVisual Studio Code、Atom以外にも多様な選択肢があるため、自分が馴染んでいるエディタやIDEにもTypeScript用プラグインが存在しないか試してみるとよいでしょう。
多様な選択肢がある理由ですが、TypeScriptは単なるコンパイラ以外のさまざまな機能を持っています。たとえば、ソースコードをフォーマットする機能だとか、入力補完候補を生成する機能です。これら、エディタの機能実装をサポートする強力で便利な要素があるため、本家Visual Studioと比べ、遜色ない強力な補完機能を備えたエディタが多く存在しているわけです。
とはいえ、エディタやプラグイン毎にTypeScript本体への追従度や完成度に差があるため、「イマイチ使いにくいな…」と思ったら別のエディタを試してみるのがよいでしょう。
本記事では、筆者がメインで使っているVisual Studio CodeとAtomについて解説します。
Visual Studio Code
VSCはMicrosoftが作ってはいますが、Electron上に構築されたマルチプラットフォームのエディタです。本家Visual Studioと違い、プラットフォームの縛りはありませんし、無料です。オープンソースではないため、自力で機能追加やバグ修正ができないのは難点ではあります。
grunt-tsconfig-updateかgulp-tsconfig-updateとの併用が前提になりますが、正しいtsconfig.jsonさえ作ってしまえばさすが本家Microsoft製だけあって、期待どおりに正しく入力補完やエラーの報告を行ってくれるようになります。特に強い要望がなく、gruntまたはgulpの利用に抵抗がないのであればVSCを最初に試してみるのがよいでしょう。
Atom + atom-typescript
AtomはGitHubが作っているエディタです。atom-typescriptプラグインを併用することで大変便利なTypeScript開発環境として利用することができます。
まとめ(開発環境編)
タスクランナーの設定とエディタの設定が終わり、JavaScriptとは比較にならぬリッチな開発環境を手に入れられたことでしょう。何か疑問や要望がある場合、サンプルリポジトリのIssueまでお寄せいただければ、筆者の人生がつらくなっていなくてTypeScriptに飽きていない限り、対応できると思います。今のところTypeScriptは3年近く飽きていないので、もうしばらくは飽きないと思うんですよね。
次回は、いよいよECMAScript 2015なコードをTypeScriptで書き始めていきます。