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:慣れるとそこまででもない?