{"id":403,"date":"2022-08-30T15:00:46","date_gmt":"2022-08-30T15:00:46","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2013\/11\/09\/google-closure-trouble-type-checking-parameters-that-should-be-functions-collection-of-common-programming-errors\/"},"modified":"2022-08-30T15:00:46","modified_gmt":"2022-08-30T15:00:46","slug":"google-closure-trouble-type-checking-parameters-that-should-be-functions-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2022\/08\/30\/google-closure-trouble-type-checking-parameters-that-should-be-functions-collection-of-common-programming-errors\/","title":{"rendered":"Google closure: trouble type checking parameters that should be functions-Collection of common programming errors"},"content":{"rendered":"<p>I&#8217;m messing around with the type checking in google&#8217;s closure compiler. The type system seems useful, if perhaps not the most sophisticated out there. I&#8217;m happy with most of the limitations, but this one just seems a bit weird.<\/p>\n<p>I&#8217;m seeing problems giving type annotations for functions passed as arguments. In particular, if the type of the passed function is itself not fixed. So for example, I&#8217;d like to write code similar to this:<\/p>\n<pre><code>\/**\n * @param {Array} xs\n * @param {function(*) : boolean} f\n * @return {Array}\n *\/\nvar filter = function (xs, f) {\n    var i, result = [];\n    for (i = 0; i &lt; xs.length; i += 1) {\n        if (f(xs[i])) {\n            result.push(v);\n        }\n    }\n    return result;\n};\n\nfilter([1,2,3], function (x) { return x &gt; 1; });\n<\/code><\/pre>\n<p>Passing &#8220;&#8211;js_error checkTypes&#8221; to the compiler, I get this:<\/p>\n<pre><code>test.js:17: ERROR - left side of numeric comparison\nfound   : *\nrequired: number\n    filter([1,2,3], function (x) { return x &gt; 1; });\n                                          ^\n<\/code><\/pre>\n<p>So, what&#8217;s wrong? Can I specify that a parameter ought to a function with one argument, without specifying the type of that argument? Am I doing something wrong, or is this just a limitation of the type checker?<\/p>\n<p>Chad suggests annotating the anonymous function passed to filter to help the type-inference out a bit:<\/p>\n<pre><code>filter([1,2,3], function (x) { return \/** @type {number} *\/ (x) &gt; 1; });\n<\/code><\/pre>\n<p>That works ok for filter(), but it seems a little unsatisfying (why does the compiler need that annotation?), and doesn&#8217;t work for more complex cases. For example:<\/p>\n<pre><code>\/**\n* @param {Array|string} as\n* @param {Array|string} bs\n* @param {function(*, *): *} f\n* @return {Array}\n*\/\nvar crossF = function (as, bs, f) {};\n\n\/**\n* @param {Array|string} as\n* @param {Array|string} bs\n* @return {Array}\n*\/\nvar cross = function (as, bs) {};\n\nvar unitlist = crossF(['AB', 'CD'], ['12', '34'], cross);\n<\/code><\/pre>\n<p>It seems like the type of everything here should be apparent to the compiler. And in fact it complains directly about matching the type of the function parameter:<\/p>\n<pre><code>test.js:52: ERROR - actual parameter 3 of crossF does not match formal parameter\nfound   : function ((Array|null|string), (Array|null|string)): (Array|null)\nrequired: function (*, *): *\nvar unitlist = crossF(['ABC', 'DEF', 'GHI'], ['123', '456', '789'], cross);\n<\/code><\/pre>\n<p>Accepted answer below addresses this case.<\/p>\n<ol>\n<li>\n<p>Change the declaration of the filter from &#8220;<em>&#8221; (everything) to &#8220;?&#8221; (unknown). The compiler only checks known types. So when the compiler tries to infer the function signature for the function expression at the call site, it resolves the parameter &#8220;x&#8221; to &#8220;?&#8221; (an unknown type) (which can be used as anything), instead of &#8220;<\/em>&#8221; (every possible type) which often needs to be restricted before use:<\/p>\n<pre><code>\/**\n * @param {Array} xs\n * @param {function(?) : boolean} f\n * @return {Array}\n *\/\nvar filter = function (xs, f) {\n    var i, result = [];\n    for (i = 0; i &lt; xs.length; i += 1) {\n        if (f(xs[i])) {\n            result.push(v);\n        }\n    }\n    return result;\n};\n<\/code><\/pre>\n<\/li>\n<li>\n<p>When there are no annotations on a function, the compiler assumes that it can take a variable number of arguments of any type and return any type. For this reason, many of the extern functions are annotated like this:<\/p>\n<pre><code>\/** @return {undefined} *\/\nfunction MyFunction() {}\n<\/code><\/pre>\n<p>This way they will properly type check.<\/p>\n<p>For your case, the easiest solution is to type cast the argument to a number inside the function (note the extra parenthesis which are required):<\/p>\n<pre><code>filter([1,2,3], function (x) { return \/** @type {number} *\/ (x) &gt; 1; });\n<\/code><\/pre>\n<\/li>\n<li>\n<p>One common approach is to use the type annotation <code>{!Function}<\/code>, which accepts any function object.<\/p>\n<p>The issue with the ALL type (*) has been reported here: Issue 708<\/p>\n<\/li>\n<\/ol>\n<p id=\"rop\"><small>Originally posted 2013-11-09 19:01:45. <\/small><\/p>","protected":false},"excerpt":{"rendered":"<p>I&#8217;m messing around with the type checking in google&#8217;s closure compiler. The type system seems useful, if perhaps not the most sophisticated out there. I&#8217;m happy with most of the limitations, but this one just seems a bit weird. I&#8217;m seeing problems giving type annotations for functions passed as arguments. In particular, if the type [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-403","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/403","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=403"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/403\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=403"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=403"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=403"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}