Google のクロージャ コンパイラの型チェックをいじっています。型システムは、おそらく最も洗練されたものではないにしても、有用に思えます。ほとんどの制限には満足していますが、これは少し奇妙に思えます。
引数として渡された関数に型注釈を付ける際に問題が発生しています。特に、渡された関数の型自体が固定されていない場合。たとえば、次のようなコードを書きたいとします。
/**
* @param {Array} xs
* @param {function(*) : boolean} f
* @return {Array}
*/
var filter = function (xs, f) {
var i, result = [];
for (i = 0; i < xs.length; i += 1) {
if (f(xs[i])) {
result.push(v);
}
}
return result;
};
filter([1,2,3], function (x) { return x > 1; });
「--js_error checkTypes」をコンパイラに渡すと、次のようになります。
test.js:17: ERROR - left side of numeric comparison
found : *
required: number
filter([1,2,3], function (x) { return x > 1; });
^
それで、何が問題なのですか?引数の型を指定せずに、1 つの引数を持つ関数にパラメーターを指定することはできますか? 私は何か間違ったことをしていますか、それともこれは型チェッカーの単なる制限ですか?
チャドは、フィルターに渡される無名関数に注釈を付けて、型推論を少し支援することを提案しています。
filter([1,2,3], function (x) { return /** @type {number} */ (x) > 1; });
これは filter() では問題なく機能しますが、少し満足できないように思われ (なぜコンパイラはその注釈を必要とするのでしょうか?)、より複雑なケースでは機能しません。例えば:
/**
* @param {Array|string} as
* @param {Array|string} bs
* @param {function(*, *): *} f
* @return {Array}
*/
var crossF = function (as, bs, f) {};
/**
* @param {Array|string} as
* @param {Array|string} bs
* @return {Array}
*/
var cross = function (as, bs) {};
var unitlist = crossF(['AB', 'CD'], ['12', '34'], cross);
ここにあるすべてのタイプは、コンパイラーに明らかであるように思われます。実際、関数パラメーターの型の一致について直接不平を言っています。
test.js:52: ERROR - actual parameter 3 of crossF does not match formal parameter
found : function ((Array|null|string), (Array|null|string)): (Array|null)
required: function (*, *): *
var unitlist = crossF(['ABC', 'DEF', 'GHI'], ['123', '456', '789'], cross);
以下の受け入れられた回答は、このケースに対処しています。