TypeScript の型定義からコードを自動生成するツールを作った

## はじめに

プログラマーなら誰しも、YAML や JSON、XML、Excel ファイル、あるいは独自の DSL などで書いた定義ファイルからコードを自動生成するツールを使用した経験があると思います。

でも、JSON、XML を手で書いていくのはつらい。独自 DSL は覚えるのがつらい。YAML も凝ったことやろうとするとカスタムタグとかいろいろ用意したりしないといけなくて、独自 DSL 化してつらい。Excel ファイルは……

ということで、みんな大好き TypeScript の表現力豊かな記法でそういった定義ファイルが書けて、コードを自動生成できたら幸せなんじゃないだろうかと思い、年末あたりに時間をかけて [typhen](https://github.com/shiwano/typhen) というツールを作ってみました。

今回はそのご紹介です。

## 使い方
たとえば、`typings/definitions.d.ts` に下記のようなインターフェイスがあって、そこから JSON Schema を生成したい場合。

```ts
interface Product {
  /** The unique identifier for a product */
  id: integer;
  /** Name of the product */
  name: string;
  /**
    @minimum 0
    @exclusiveMinimum
   */
  price: number;
  /**
    @minItems 1
    @uniqueItems
   */
  tags?: string[];
}
```

### typhen のインストール

`$ npm install -g typhen`

### Plugin のインストール

`$ npm install --save-dev typhen-json-schema`

ここでは、TypeScript の型定義を JSON Schema に変換する [typhen-json-schema](https://github.com/shiwano/typhen-json-schema) というプラグインをインストールしています。npm に publish されたプラグイン以外に、自作プラグインなども使うこともできるので、そういう場合はプラグインをインストールする必要はありません。

### typhenfile.js の作成

プロジェクトフォルダ直下に `typhenfile.js` という名前のファイルを作って以下のようなコードを書きます。

```js
module.exports = function(typhen) {
  var plugin = typhen.loadPlugin('typhen-json-schema', {
    baseUri: 'http://example.com/my-schema'
  });

  return typhen.run({
    plugin: plugin,
    src: 'typings/definitions.d.ts',
    dest: 'generated'
  });
};
```

### typhen の実行

`$ typhen`

これで `generated/product.json` というファイル名で JSON Schema が生成されます。

```json
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "Product",
  "description": "A product from \"Acme\"'s catalog ",
  "type": "object",
  "properties": {
    "id": {
      "description": "The unique identifier for a product ",
      "type": "integer"
    },
    "name": {
      "description": "Name of the product ",
      "type": "string"
    },
    "price": {
      "minimum": 0,
      "exclusiveMinimum": true,
      "type": "number"
    },
    "tags": {
      "minItems": 1,
      "uniqueItems": true,
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "additionalProperties": false,
  "required": ["id", "name", "price"]
}
```

このように TypeScript の型定義から特定のコードを生成するツールが、typhen になります。

## 使い方その2

```bash
$ npm install -g typhen typhen-json-schema
$ typhen --plugin typhen-json-schema --dest generated definitions.d.ts
```

上記のようなやり方でも変換はできます。

## その他解説

### プラグインの作り方は？
ドキュメントはまだありません。[typhen-json-schema](https://github.com/shiwano/typhen-json-schema) とか [README](https://github.com/shiwano/typhen#plugin)、 [テストで使ってるプラグイン](https://github.com/shiwano/typhen/tree/master/test/fixtures/plugin) とか見て、いろいろと察してもらえると……

### TypeScript で書いたコードのドキュメントも生成できるの？
`*.ts` ファイルからもコード生成できるので、できます。

### Generics は使えるの？
使えます。一つ注意点があって、Ruby や PHP など型のない言語向けのコードを生成するときには、ジェネリック型に型パラメータを与えて生成した型に独自の名前を付ける必要があります。そういう場合 typhen は、たとえば `Dictionary<T>` という型があって、`Dictionary<number>` という型が生成されていた時には、その型に `DictionaryWithNumber` という型名を付けます。

### オブジェクト型リテラルとかは使えるの？
使えます。これも Generics の時と同様に、独自の命名規約によって型の名前は付けられます。たとえば `function getText(): { text: string };` という定義があった場合、`{ text: string }` という型には `GetTextObject` という型名が付けられます。

### それ以外のあの機能は？
`*.d.ts` で表現できる型情報については、基本的に全部 Handlebars テンプレートでレンダリングできるようにしていきたいと思っているので、何か不足があれば教えてください。

## 今後について
プライベートでコードを自動生成するときにはなるべくこのツールを使っていきたいなと思っているので、メンテはちゃんとやります。直近でやりたいなと思っていることは、以下の通り。

* TypeScript v1.4.1 の対応
* gulp, grunt のプラグインを作る
* Browserify
* ドキュメントを充実させる

他にもこういうのもあった方がいいんじゃないの、というのがあったら教えてください。

## おわり
typhen のご紹介はこれで終わりです。もしこの記事見て、自分も typhen 使ってみたというチャレンジャブルな方がいらっしゃったら、お気軽にフィードバックくださると嬉しいです(´・ω・`)