TypeScript 1.0のリリースを機に、ちょっとJavaScript方面にも手を出してみようかということで、最近はわかめ本を読みながらチマチマとコードを書いております。

- 作者: わかめまさひろ,井上章,丸山弘詩
- 出版社/メーカー: インプレスジャパン
- 発売日: 2014/05/16
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
今日は技評さんのjQuery記事をTypeScriptで写経しながら読み進めていました。
もちろんjquery.d.tsを使って型チェックを利かせながらの写経です。メソッドがサジェストされるのもなかなか気持ちが良いですが、 ajax(settings: JQueryAjaxSettings) への渡し値であるJQueryAjaxSettingsがしっかり定義されているため、キーがサジェスト&プロパティ存在チェックされるわ、値に型チェックが入るわで、超気持ちいい感じです。
しかし、こうも型で守られた中で写経していると、むしろ型が付いていないところが気になってしまいます。特に今回の写経では、ジェネリクスが利いている each<T>(collection: T[], callback: (indexInArray: number, valueOfElement: T) => any): any; にany型のcollectionを渡してしまうのは、型の確定を心待ちにしているであろう valueOfElement さんにあまりにも申し訳が立たないと感じました。
というわけで、自前でインターフェースによる型定義を行ってみることにしました。YouTubeのAPIから返ってくるJSONは、本来ならばそれなりに複雑ですが、今回の例に使う部分だけならば、下記のようなJSONを想定すれば充分でした。
{
"feed": {
"entry": [
{
"media$group": {
"media$player": [{"url": "http://hogehoge"}],
"media$thumbnail": [{"url": "http://fugafuga"}]
}
},
...
]
}
}
で、実際に写経してみたのが以下になります。
YouTubeResponseとFeedまでは真面目に書いていたのですが、途中から面倒くさくなってEntryインターフェースではエイヤッと超適当に書いてみたら通って逆にびっくり。構造的部分型の真骨頂を垣間見たような気がします。
そんなわけで、successに定義した関数は、JavaScript版と変わりなく書かれているように見えますが、
- ジェネリクスによる型の確定(
data.feed.entryはEntry[]型であり、itemはEntry型である) - 型チェック(
group.media$playerは配列である) - パラメータ存在チェック(
group.media$player[0]はurlというパラメータを持つ)
のようなことがコンパイル時に行われています。タイポしたり、存在しないメソッドやパラメータを勝手に生やすと速攻で叱られるので、私のようなゆとりプログラマーでも安心してコードを書くことができますね。
まとめ
構造的部分型を活用してインターフェースを定義すると大変捗る!!!
おまけ
むりやり1つのインターフェースにまとめてみた。可読性はクソ悪い*1けど、TypeScriptの型システムとしては、これでもOK。
interface YouTubeResponse {
feed: {
entry: Array<{
media$group: {
media$player: Array<{url: string;}>;
media$thumbnail: Array<{url: string;}>;
};
}>;
};
}
*1:慣れるとそこまででもない?