latest log

酩酊状態で書いたエンジニアポエムです。酩酊状態で読んでください。

TypeScript の Interface が mofmof.js にもほしい

TypeScript を知ってる前提で書きますよー

(ε・◇・)з TypeScript いいですねー、JavaScriptの上位互換でES6と衝突しない感じでステキですねー。
(ε・◇・)з Interface とかもいいですねー。とりいれたいですねー

Interface を mofmof.js に実装してみました

// TypeScript Style
interface Point {
    x: number;
    y: number;
}
// mofmof.js Style
mm.Interface("Point", {
    x: "number",
    y: "number"
});

(ε・◇・)з モニターから3メートルぐらい離れてみれば、ほぼ同じだね!

実行してみました

以下のコードを実行すると、mm.allow({ x: 1 }, "Point"); の行でアサーションが発生し、ブラウザのコンソールに以下の情報を表示します。

  • testInterface 関数内でエラーが発生した
  • interface Point に合致していない変数が渡された
  • interface Point の詳細はこれ

http://mofmof-js.googlecode.com/svn/trunk/test/mm.js.htm とかで実行できます。

function testInterface() {
    mm.Interface("Point", { x: "number", y: "number" });

    mm.allow({ x: 1, y: 2, z: 3 }, "Point"); // ok
    mm.allow({ x: 1, y: 2       }, "Point"); // ok
    mm.allow({ x: 1             }, "Point"); // -> assert
}

testInterface();
  [2012-10-05T07:42:34.067Z]:TypeError: 

>>> testInterface in mm.allow({"x":1}, Point)

interface Point {
    "x": "number",
    "y": "number"
}

    at Function.mm_allow [as allow] (js_src/mm.js:1234:23)
    at js_src/aa.htm:58:8 mm.js:1383

Uncaught TypeError: ASSERTION

(ε・◇・)з o O ( mofmof.js は js生成言語と違って静的解析がないので
(ε・◇・)з o O ( このように全部動的にチェックする感じになりますねー

追記

TypeScript には「変数が複数の型を取る場合にAny型になってしまい型チェックの恩恵を受けられない」という問題があるようです。
TypeScript はコンパイルしてしまうと型情報が落ちるようなので、Any型の変数をチェックするのはユーザの責務になります。

mofmof.js では、"number/string" のようにスラッシュで区切り、複数の型や インターフェース名, クラス名 を指定できます。

// mofmof.js style
mm.Interface("Scale", {
    width:  "number/string",
    height: "Number/String"
});
// TypeScript style
interface Scale {
    width:  any;
    height: any;
}

// インターフェース定義に、他のインターフェースを指定する事もできます。
mm.Interface("Matrix2D", {
    scale: "Scale", // Scale Interface を制約として与える
    m11: "number",
    m33: "number"
});

mm.Interface("TextColor", {
    setTextColor: "function",
    getTextColor: "function"
});

// クラス定義時に Interface による制約を加えられます。
mm.Class("Canvas:Matrix2D:TextColor", { // Canvas implements Matrix2D, TextColor
    m11: 0,
    m33: 0,
    scale: { width: 0, height: 0 },
    init: function() {},
    setTextColor: function(color) {},
    getTextColor: function() {}
});

mm.Class("Canvas3D:Canvas", { // Canvas3D extends Canvas
    init: function() {}
});

mofmof.js の型一覧

mm.allow は mm.allow(mix, "string/number/undefined") のように使う assert 用の関数です。実行時に動的に型をチェックします。

以下は、mm.allow, mm.Interface に指定可能な型の一覧です。*1

  • "undefined", "null", "node", "global"
  • "string", "number", "boolean", "array", "regexp", "date", "object", "function"
  • "list" (NodeList, HTMLCollection, Arguments)
  • "attr" (NamedNodeMap)
  • "style" (CSSStyleDeclaration)
  • mm.Class で定義したクラス名
  • mm.Interface で定義したインターフェース名
  • function Hoge(){}; new Hoge; で生成した野良クラス名

型名の取得は mm.type(mix) で行います。

むむむ

メソッドの引数と戻り値の型を Interface で定義できたら良いのですが。

このクラスの Interface を

mm.Class("Canvas:TextColor", {
    setTextColor: function(color) {},
    getTextColor: function() {}
});

こう定義できたらいいですね。

// 今はこう
mm.Interface("TextColor", {
    setTextColor: "function",
    getTextColor: "function"
});
// できたらこんな感じに
mm.Interface("TextColor", {
    setTextColor: "function(color:Color)",
    getTextColor: "function():Color"
});

*1:クラス名とインターフェース名は大小文字を区別します