hagino3000's blog

平成アーカイブス (更新停止)

JavaScriptで厳格な型チェックを行なうライブラリを書いた

(追記) Version 0.3をリリースしました。

先日のjava-ja温泉で「JavaScriptは独りでヒャッハーするのには良いけど、複数人で開発しだすと途端にカオスになって苦労する」という話になった。それに対する解の一つはClosure Compilerが採用したアノテーションによる型の定義と静的チェックだろう。それとは別のアプローチで何かできないかなと考えていたら、ECMAScript 6にObjectのプロパティアクセスをフックできる仕組み(Proxy.create)があったのを思い出した。Proxy APIを使ってみたら型チェックが効くC言語の構造体みたいな物が作れたのでライブラリ化した。

これを使うと何が良いかというと

obj = {};
obj.hogeFuga = new Foo();

// do something

obj.hoge_fuga = null; // 不要になったので解放 (タイプミス)

といった、動かしてもすぐには気づきにくいミスに例外を投げてくれる。Object.seal でも良いけど、未定義プロパティのreadに対しては何もしてくれないのが不満だったので、それも例外が飛ぶようにした。

使い方は次の通り。Object.defineProperties に似せた。

// 構造体の定義
Struct.define('Position', {
  x: {type: 'number'},
  y: {type: 'number'}
});

Struct.define('Square', {
  name: {type: 'string', writable: false},
  pos: {type: 'struct:Position'},
  hidden: {type: 'boolean'}
});

// 作成
var sq = Struct.create('Square', {
  name: 'mySquare',
  hidden: true
});

// 通常のObjectと同様に扱える
sq.pos = Struct.create('Position', {x: 10, y: 20});
sq.hidden = false;
console.log(sq.name); // => mySquare
console.log(sq.pos.x); // => 10

// 以降の操作は全てチェックエラー
var name = sq.Name; // 未定義プロパティの読み取り
delete sq.Name; // 未定義プロパティのdelete
sq.visible = true; // プロパティの追加
sq.pos.x = "100"; // 型の不一致
sq.name = "hoge"; // 読み取り専用プロパティの変更

動作にはECMAScript 6 のProxyが必要なので、Firefox or 設定をいじったChromeじゃないと動かない。しかしProxyが無くても例外が飛ばないだけなので問題は無い、開発時にエラーが飛んでくれればそれで良いと考えているので。

(追記) ChromeでProxyを有効にする方法を書きました。