谷歌关闭:故障类型检查应该是功能的参数

时间:2012-04-12 20:15:57

标签: javascript types google-closure-compiler typechecking

我正在搞乱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; });
                                          ^

那么,怎么了?我可以指定一个参数应该是一个带有一个参数的函数,而不指定该参数的类型吗?我做错了什么,或者这仅仅是类型检查器的限制?


Chad建议对传递给过滤器的匿名函数进行注释,以帮助进行类型推理:

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 个答案:

答案 0 :(得分: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;
};

答案 1 :(得分:3)

当函数没有注释时,编译器假定它可以采用任意类型的可变数量的参数并返回任何类型。出于这个原因,许多外部函数都注释如下:

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

这样他们就可以正确地打字了。

对于您的情况,最简单的解决方案是将参数类型转换为函数内的数字(请注意所需的额外括号):

filter([1,2,3], function (x) { return /** @type {number} */ (x) > 1; });

答案 2 :(得分:2)

一种常见的方法是使用类型注释{!Function},它接受​​任何函数对象。

此处报告了ALL类型(*)的问题:Issue 708

答案 3 :(得分:1)

对我来说这看起来像个错误。你应该在这里提交:   http://code.google.com/p/closure-compiler/issues/list

如果你没有指定类型,它应该是“未知”(?)而不是“任何”(*)。编译器不会(或不应该)键入检查未知类型的使用。