skip to Main Content

I have a function which takes in two parameters, something like:

function example(type, val) {
  // handle "val" based on "type"
}

The acceptable types for val depend on type. The type parameter will always be one of a few select strings. For example, my JSDoc may look something like the following:

/**
 * Handles the value of "val" based on the "type" parameter.
 * @function example
 * @param {"number" | "string" | "boolean"} type - The type of the "val" parameter.
 * @param { ????? } val - The value to handle.
 * @returns {void}
 */
function example(type, val) {
  // handle "val" based on "type"
}

It’s worth noting that "number", "string", and "boolean" aren’t actually the allowed values of type in my real code; I’m only using them here for demonstration as it makes the problem easier to understand.

As seen in the above code, type can take on a few select values. If type="number", for example, then val should only be allowed to be a number.

I thought I could union a few typedefs together to achieve the result I’m looking for, but I wasn’t entirely sure how this would even work as I’m dealing with functions, not objects.

Any suggestions would be appreciated!

2

Answers


  1. Chosen as BEST ANSWER

    Just discovered the @overload tag, which seems to do what I need:

    /**
     * Handles the value of "val" based on the "type" parameter.
     * @function example
     * @overload
     * @param {"number"} type - The type of the "val" parameter.
     * @param {number} val - The value to handle.
     * @returns {void}
     */
    /**
     * Handles the value of "val" based on the "type" parameter.
     * @function example
     * @overload
     * @param {"string"} type - The type of the "val" parameter.
     * @param {string} val - The value to handle.
     * @returns {void}
     */
    /**
     * Handles the value of "val" based on the "type" parameter.
     * @function example
     * @overload
     * @param {"boolean"} type - The type of the "val" parameter.
     * @param {boolean} val - The value to handle.
     * @returns {void}
     */
    function example(type, val) {
      // handle "val" based on "type"
    }
    

    Not entirely sure why this isn't documented on the JSDoc website, but it seems to work with IntelliSense on VS Code.


  2. Ok. I think now, after some comments I get what you want.

    /**
     * Handles the value of `value` based on the `type` parameter.
     * 
     * @template { string } TYPE
     * @template { unknown } VALUE
     * 
     * @param { TYPE } type
     * @param { VALUE } value
     * 
     * @returns
     */
    function example ( type, value )
    {
       // Mock result:
       const mocked =
       {
          /**
           * @param { string } eventName
           * @param { ( value: VALUE ) => any } callBack
           */
          on: ( eventName, callBack ) =>
          {
             // Handle the event attachment here.
          }
       };
       
       return mocked;
    }
    

    Example of JSDoc

    Also, there’re more two (+1) examples that could be helpful.

    1st case is that you want to produce IntelliSense error if the value is not of the same type as the given in the type parameter. I recommend directly using classes here.

        // 1st case:
        /**
         * Handles the value of `value` only if it matches `type` parameter type.
         * 
         * @template { typeof Boolean | typeof Number | typeof String } TYPE
         * @template { InstanceType < TYPE > } VALUE
         * 
         * @param { TYPE } type - The type of the `value` parameter.
         * @param { VALUE } value - The value to handle.
         * 
         * @returns
         */
        function example ( type, value )
        {
           if ( Object(value) instanceof type )
           {
              // Handle the value...
           }
           
           else
           {
              // Ignore or do something else.
           }
        }
    
        example(String, 1);
        //--------------^
        // IntelliSense will shown an error here if
        // `// @ts-check` is in the first line of
        // the file.
    
        example(Number, 1);
        //--------------^
        // IntelliSense will not shown an error here
        // if `// @ts-check` is in the first line of
        // the file, because second parameter type
        //.matches the class in the first parameter.
    

    2nd case is that you want to parse your value differently depending on what type is. Note that in this case (example2) I’ve kept the type parameter type as string.

        // 2nd case:
        /**
         * Handles the value of `value` based on the `type` parameter.
         * 
         * @param { 'boolean' | 'number' | 'string' } type - The type of the `value` parameter.
         * @param { any } value - The value to handle.
         * 
         * @returns
         */
        function example2 ( type, value )
        {
           switch ( type )
           {
              case 'boolean':
              {
                // Handles value as a boolean.
                break;
              }
              
              case 'number':
              {
                // Handles value as a number.
                break;
              }
              
              case 'string':
              {
                // Handles value as a string.
                break;
              }
              
              default:
              {
                throw new TypeError('Can not parse the value because it does not match the type given.');
                break;
              }
           }
        }
    
        example2('string', 1);
        // Does not show errors. Will parse `1` as a string.
        
        example2('array', {});
        // Does not show errors. Will throw a TypeError
        // because `array` is not allowed as a type.
    

    3rd case is a suggestion based on the comments.

       // 3rd case:
       /**
        * Handles the value of `value` based on the `type` parameter.
        * 
        * @param { string } type - The type of the `value` parameter.
        * @param { object } value - The value to handle.
        * 
        * @returns
        */
       function example3 ( type, value )
       {
          // I highly recommend using the class in the `type` instead of a string.
          
          if ( Object(value).constructor.name.toLowerCase() == type.toLowerCase()  )
          {
             // Only parses if the value constructor's name is equals to `type`.
          }
          
          else
          {
             // Ignores or do something else.
          }
       }
    

    NOTE: You can actually mix those two approaches.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search