3

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);

以下の受け入れられた回答は、このケースに対処しています。

4

4 に答える 4

4

フィルターの宣言を " *" (すべて) から " ?" (不明) に変更します。コンパイラは既知の型のみをチェックします。そのため、コンパイラが呼び出しサイトで関数式の関数シグネチャを推測しようとすると、パラメーター "x" が "?" に解決されます。(不明な型) (何としてでも使用できます)、使用前に制限する必要があることが多い "*" (考えられるすべての型) の代わりに:

/**
 * @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;
};
于 2012-04-20T00:53:03.237 に答える
3

関数に注釈がない場合、コンパイラは、任意の型の可変数の引数を取り、任意の型を返すことができると想定します。このため、extern 関数の多くは次のように注釈が付けられています。

/** @return {undefined} */
function MyFunction() {}

このようにして、彼らは適切にチェックをタイプします。

あなたの場合、最も簡単な解決策は、引数を関数内の数値に型キャストすることです(必要な余分な括弧に注意してください):

filter([1,2,3], function (x) { return /** @type {number} */ (x) > 1; });
于 2012-04-13T23:15:50.000 に答える
2

{!Function}一般的なアプローチの 1 つは、任意の関数オブジェクトを受け入れる 型注釈を使用することです。

ALL タイプ (*) に関する問題は、ここで報告されています: Issue 708

于 2012-04-13T21:34:13.643 に答える
1

これは私にはバグのように見えます。ここにファイルする必要があります: http://code.google.com/p/closure-compiler/issues/list

タイプを指定しない場合は、「任意」(*) ではなく「不明」(?) にする必要があります。コンパイラは、不明な型の使用を型チェックしません (またはすべきではありません)。

于 2012-04-13T16:53:03.687 に答える