0

Is there a proper syntax for documenting optional JavaScript parameters, where the optional parameter comes in the middle of the function header (think jQuery, Gulp, etc.)

I've documented the function in the standard way and that works fine. The catch is when I try to set the second parameter to last variable (in the case where the optional parameter wasn't used), my IDE gets confused.

Example:

/**
 * @param {number} a_num
 * @param {string} [a_str='']
 * @param {{}} a_obj
 */
function (a_num, a_str, a_obj) {
    if (!a_obj) a_obj = a_str; // doesn't want me to save a string to an object.
    a_str = '';
    // more stuff
}

If it matters, I'm using PHPStorm by JetBrains, which uses the Google Closure style of docs (mainly). Though I'm looking for a more general, best practice approach.

I suspect I could do something ugly like:

/**
 * @param {number} a_num
 * @param {string|{}} a_str
 * @param {{}} [a_obj=null]
 */

But that doesn't really describe the situation as accurately as I'd like. I'm hoping since this is becoming a common structure that there is something to handle it properly.

Jamiec
  • 118,012
  • 12
  • 125
  • 175
samanime
  • 21,211
  • 7
  • 69
  • 122
  • 2
    I have two down votes and one attempt to close for being unclear. I understand that optional parameters in the middle of a function header are taboo (or downright impossible) in most languages, but in JavaScript it is a valid and frequently used pattern, so I think this is a valid question. As for being unclear, if someone could leave a comment letting me know what's unclear, I'd be happy to update the question. Thanks. – samanime Feb 10 '15 at 00:05
  • 1
    There are lots of things that you can do in javascript but just because the language allows it doesn't mean it is good practice. For example javascript allows global variables where as many languages do not, that doesn't mean it is a good idea to use lots of global variables in JS. – bhspencer Feb 10 '15 at 01:00
  • I have deleted my answer as it is not really answering your question but I am adding it here as a comment as I think it is still a relevant part of the conversation: I consider it bad practice to put optional parameters in the middle of the parameter list. It may increase the confusion of the users of your API. Instead consider either putting the optional param at the end of the params or pass in an options object rather than a list of params. – bhspencer Feb 11 '15 at 17:35
  • @bhspencer: Fair enough, and I don't strictly disagree with you either. The one valid use case where I think it helps bring clarity overall is when the last parameter is a callback, which allows for cleaner and easier to read anonymous functions to be passed in. Thanks. – samanime Feb 11 '15 at 17:58
  • I would discourage the use of anonymous functions in general. I mostly share these opinions from Todd Motto http://toddmotto.com/avoiding-anonymous-javascript-functions/ – bhspencer Feb 11 '15 at 18:45
  • 1
    @bhspencer I agree with that mostly as well. However, there are some valid times and places for anonymous callbacks. The particular instance I'm thinking of, which also happens to be the use-case for the function I asked this question about, is for a function used in a gulp task. Gulp tasks are generally simple, and the function would never need to be reused. Using callbacks in this scenario improves readability. – samanime Feb 11 '15 at 18:57
  • possible duplicate of [How to document variable number of parameters in certain situations with JSDoc](http://stackoverflow.com/questions/25605557/how-to-document-variable-number-of-parameters-in-certain-situations-with-jsdoc) – Louis Feb 12 '15 at 15:49

1 Answers1

1

Annotating optional parameters in the middle of a function's parameter list are almost as challenging as maintaining code that uses this type of method signature.

  1. Javascript doesn't truly support optional parameters in the middle of a function's argument list (to do that you need named parameters). Instead, functions that advertise this try to discern which version of the function was called based on the number and values of the parameters.

  2. Javascript also doesn't support function overloading.

Recognizing these limitations gives the first clues to supporting what is in essence a documentation strategy. Your annotation must support all types of calls - and by doing this you lose a certain amount of type safety when using a tool that enforces or checks types.

Let's use one of the jQuery.prototype.bind signatures as an example:

jQuery.prototype.bind( eventType [, eventData ], handler )

To document this method, we recognize that two parameters are always required. First let's rearrange and rename the parameters:

jQuery.prototype.bind( eventType, eventDataOrHandler, [ handler ] )

With that rearrangement, the JSDoc becomes clearer:

/**
 * @param {string} eventType
 * @param {(*|function(Event))} eventDataOrHandler
 * @param {function(Event)=} handler
 * @return {!jQuery}
 */
jQuery.prototype.bind =
    function(eventType, eventDataOrHandler, handler) {};

Unfortunately there is no way to specify that when three arguments are used one set of types is needed, and a different set when two arguments are used.

Perusing the Closure-compiler jQuery externs will give you plenty of examples.

Chad Killingsworth
  • 14,140
  • 2
  • 32
  • 52
  • Thanks. That's kind of what I thought already. Was hoping something more magical, but makes total sense. Luckily what I'm documenting is only one function, so not too terrible. – samanime Feb 13 '15 at 17:05
  • 2
    @doc I'm pretty sure people don't like the idea of my question and are having trouble differentiating not liking the contents of the question (and answer) vs. a poorly written question. – samanime Feb 18 '15 at 17:25