TypeScript の仕様を眺めた
- TypeScript - JavaScript that scales.
- MicrosoftがJavaScript系の新言語「TypeScript」を発表、C#の父が開発 | 日経 xTECH(クロステック)
TypeScript、JavaScript とある程度互換性あるし、読みやすい JavaScript のコードに変換してくれるし、既に実験場も仕様書もあってすごい。
ということでちょっと仕様書をざっと眺めてみました。そのときに面白いなーとか思ったのとかをメモ。
Structual Subtyping
Structual Subtyping は、静的型付けの型チェックと、動的型付けのアドホックを混ぜあわせたような、いいとこ取りの機能で、
interface Point { x: number; y: number; } function getX(p: Point) { return p.x; }
というのがあるとき、
class CPoint { constructor (public x: number, public y: number) { } } getX(new CPoint(0, 0)); // OK、p.x, p.y とアクセスすることができる getX({ x: 0, y: 0, color: "red" }); // OK、余分なフィールドがあっても同様にアクセスできる getX({ x: 0 }); // エラー、p.y とアクセスできない
こんな風に、
- とにかく p.x, p.y とアクセスできるなら何でも渡すことができる(動的型付けっぽさ)
- p.x, p.y とアクセスできないならコンパイルエラー(静的型付けっぽさ)
という感じになります。
これが実際どんなケースで嬉しいかというと、例えば jQuery。
jQuery は既に JavaScript のライブラリとして存在しているわけですが、この jQuery に対して一切変更することなく「後付けで」インターフェースを定義して、型チェックの恩恵に与れます。 (この後付け jQuery インターフェースは jquery.d.ts にあるようです)
ちなみに既存のオブジェクトに対して後で型を付ける場合、
declare var $: JQueryStatic;
とかしてやればいいようです。
型推論
引数は推論されませんが、戻り値は推論されるようです。
function f(x) { return 10; }
と書いた場合、f 関数の型は (x: any) => number です。
function f(x) { if (x == 0) return 10; else return "hoge"; }
と書いた場合、型がわからないということで、コンパイルエラーになりました(これは JavaScript と互換性のない動作)。
function f(x): any { if (x == 0) return 10; else return "hoge"; }
と書けばコンパイルは通ります(x は変わらず any 型のまま)。
アロー関数式
要するにラムダ式。
var f = x => x+1; // (x:any) => any
しかし残念なことに、普通の関数と同じく、x は any 型です。
x を使っているので、戻り値も any 型です。(any型 + number型はany型になる at 4.15.2)
マジメに型を付けるなら
var f = (x:number) => x+1; // (x:number) => number
と書きます。
マップ型
マップは、それぞれ別々の型になるようです。
function f(v:{ a:number; b:string; }) { return { x:10, y:20 }; // 戻り値は { x:number; y:number; } 型 }
配列型
var v: number[];
でいけます。2次元配列なら
var v: number[][];
です。
多相型
残念なことに自作はできないようです。
Type Assertion
要するにキャスト。
これは例えば、こういう風に使います。
var canvas = <HTMLCanvasElement>document.createElement("canvas");
document.createElement が返す型は HTMLElement なのですが、それを HTMLCanvasElement として扱うようにします。
あとは、
interface Point { x: number; y: number; } var p:Point = { x:10, y:<number>undefined };
とかすれば、型チェックは通るようになります(実際に動作するかどうかはともかく)。
クラス
public, private 指定、static 指定、継承、super を使った親クラス呼び出し、コンストラクタでメンバの定義と初期化など、普通の機能が揃ってます。
モジュール
誰か解説お願いします!