Javascript 谷歌关闭:故障类型检查参数,应该是函数

Javascript 谷歌关闭:故障类型检查参数,应该是函数,javascript,types,google-closure-compiler,typechecking,Javascript,Types,Google Closure Compiler,Typechecking,我在谷歌的闭包编译器中搞类型检查。类型系统似乎很有用,如果不是最复杂的话。我对大部分的限制都很满意,但这个似乎有点奇怪 我发现为作为参数传递的函数提供类型注释时出现问题。特别是,如果传递函数的类型本身不是固定的。例如,我想编写类似以下内容的代码: /** * @param {Array} xs * @param {function(*) : boolean} f * @return {Array} */ var filter = function (xs, f) { var i,

我在谷歌的闭包编译器中搞类型检查。类型系统似乎很有用,如果不是最复杂的话。我对大部分的限制都很满意,但这个似乎有点奇怪

我发现为作为参数传递的函数提供类型注释时出现问题。特别是,如果传递函数的类型本身不是固定的。例如,我想编写类似以下内容的代码:

/**
 * @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; });
那么,怎么了?我是否可以指定一个参数应该是一个具有一个参数的函数,而不指定该参数的类型?我是做错了什么,还是这只是类型检查器的一个限制


Chad建议注释传递给filter的匿名函数,以帮助进行类型推断:

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

下面接受的答案解决了这个问题。

这在我看来像个bug。您应在此处存档:


如果不指定类型,则应为“未知”(?)而不是“任何”(*)。编译器不会(或不应该)对未知类型的使用进行类型检查。

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


这里已经报告了ALL类型(*)的问题:

当函数上没有注释时,编译器假定它可以接受任意类型的可变数量的参数并返回任意类型的参数。因此,许多外部函数的注释如下:

/** @return {undefined} */
function MyFunction() {}
这样他们就可以正确地进行打字检查

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


将筛选器的声明从“
*
”(所有内容)更改为“
”(未知)。编译器只检查已知类型。因此,当编译器试图在调用站点推断函数表达式的函数签名时,它会将参数“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;
};
/**
*@param{Array}xs
*@param{function(?):boolean}f
*@return{Array}
*/
变量过滤器=函数(xs,f){
var i,结果=[];
对于(i=0;i
我搞错了。在函数表达式上没有显式声明类型的情况下,函数签名是从“filter”的参数声明中推断出来的,该声明将函数签名声明为“*”。将筛选函数f参数的声明更改为“function(?):boolean”很可能就是您想要的。谢谢,这样就解决了这个问题。但我并不是每次都能用这种方式解决。我将用另一个例子更新这个问题。
filter([1,2,3], function (x) { return /** @type {number} */ (x) > 1; });
/**
 * @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;
};