javascriptjsdocgoogle-closure-compiler

How to annotate an optional parameter using Google Closure Compiler?


I am very new to Google Closure Compiler (GCC). I am confused on how to make it show a parameter as optional...

Here is part of my code:

/**
 * @param {string} name The event name
 * @param {Date} date1 The start date (If alone, the single date) of the event
 * @param {Date} date2 The end date of the event
 */
function getEventLink (name,date1,date2) {
    // code here
}

I want to have date2 be optional... I found a helpful page on the Closure Compiler, but I didn't see and option for optional... is it possible? If so, how would I do it?

I've tried doing:

/**
 * @param {string} name The event name
 * @param {Date} date1 The start date (If alone, the single date) of the event
 * @param {Date|undefined} date2 The end date of the event
 */
function getEventLink (name,date1,date2) {
    // code here
}

Also, with null instead of undefined, but neither seemed to work...


Solution

  • The Google Closure Compiler relies on annotations to do its work. Because JavaScript has no syntax for types these have to be written as comments in the source files.

    These comments are written using JSDoc and even though GCC has come with its own tags over the years (e.g. @polymer isn't a "native" JSDoc tag), it does support JSDoc types expressions. (And JSDoc does support the Google Closure Type System in its type expressions too.)

    Annotation? Expression? What?!

    A simple example will clarify:

    /**
     * @param {string|number} x
     */
    const a = x => x;
    

    This is the annotation: @param {string|number} x. It is information about a thing:

    1. it is a parameter
    2. its name is x
    3. its type is either a string or a number

    This is the type expression: {string|number}. It is information about the type of a thing.

    Optional parameters in JavaScript

    As you know JavaScript allows to specify default values for parameters in the function signature:

    const a = (x=1, y=2, z=3) => x + y + z;
    

    These default values are used if and only if undefined is passed either implicitly or explicitly:

    a();
    //=> 6
    
    a(undefined, undefined, 20);
    //=> 23
    
    a(null, null, 20);
    //=> 20 (null doesn't trigger the default value and is coerced to 0)
    

    Optional parameters in JSDoc

    There are two annotations possible for an optional parameter. Just pick the one you like:

    /** @param {number=} x */
    

    or

    /** @param {number} [x] */
    

    However there is only one for an optional parameter with a default value:

    /** @param {number} [x=1] */
    

    Optional parameters with GCC

    Even though a(undefined, undefined, 20) is technically possible in JavaScript, it is however a poor developer experience and GCC may complain.

    Optional parameters without declared default values in the function signature should be last otherwise GCC will issue a warning.

    In this example z is the only non-optional parameter however it is the last parameter:

    /**
     * @param {number} [x=1]
     * @param {number} [y=2]
     * @param {number} z
     */
    const a = (x, y, z) => (x ?? 1) + (y ?? 2) + z;
    
    a(undefined, undefined, 20);
    //=> 23
    

    GCC output:

    JSC_OPTIONAL_ARG_AT_END: optional arguments must be at the end at line 11 character 10
    const a = (x, y, z) => (x ?? 1) + (y ?? 2) + z;
              ^
    

    This is of course not an issue if all parameters are optional. These examples are all OK:

    /**
     * @param {number} [x=1]
     * @param {number} [y=2]
     * @param {number} [z=3]
     */
    const a = (x, y, z=3) => (x ?? 1) + (y ?? 2) + z;
    

    or

    /**
     * @param {number} [x=1]
     * @param {number} [y=2]
     * @param {number} [z=3]
     */
    const a = (x, y, z) => (x ?? 1) + (y ?? 2) + (z ?? 3);
    

    or

    /**
     * @param {number} [x=1]
     * @param {number} [y=2]
     * @param {number} [z=3]
     */
    const a = (x=1, y=2, z=3) => x + y + z;
    

    Further readings