Search code examples
javascriptgoogle-closure-compilertypechecking

Dynamic type discovery in Google Closure Compiler


I sometimes run into the situation that I have a JavaScript object of unknown type. Then I perform a type check in script and call appropriate functions depending on the detected type. e.g. like this

/**
 * @param {!Array} aArray my array
 */
function actOnArray(aArray) {

}

/**
 * @param {*} aObject an arbitrary object
 */ 
function doSomething(aObject) {
  // make sure we have an array
  if ((null != aObject) && Array.isArray(aObject)) {
    actOnArray(aObject);
  }
}

Running this sniplet via advanced compilation in the google closure compiler yields the following warning message:

JSC_TYPE_MISMATCH: actual parameter 1 of actOnArray does not match formal parameter
found   : *
required: Array at line 14 character 15
    actOnArray(aObject);

This warning makes sense, since the compiler does not know anything about the semantic of my type check.

My question is: how can I annotate the code to tell the compiler that at a certain point I have gained information about a type. In this example I would like to tell inside the if block that I now know for sure that the aObject parameter is of type !Array.


Solution

  • For some patterns, the compiler can automatically tighten the types within tests:

    // ==ClosureCompiler==
    // @compilation_level ADVANCED_OPTIMIZATIONS
    // @output_file_name default.js
    // @warning_level VERBOSE
    // ==/ClosureCompiler==
    
    
    /** @param {*} data */
    function log(data) {
      if (data && data instanceof Array) {
        logArray(data);
      } else {
        console.log(data);
      }
    }
    
    /** @param {!Array} data */
    function logArray(data) {
      for(var i = 0; i < data.length; i++) {
        log(data[i]);
      }
    }
    
    log([1, 2, 3]);
    

    However, in many cases it cannot. In those instances you need to type cast:

    actOnArray(/** @type {!Array} */ (aObject));
    

    note the extra parenthesis - they are required