I have been using Visual Studio's JavaScript Intellisense functionality for a while now and have mostly been happy with how well it provides suggestions for standard APIs, but I have found that I cannot get Visual Studio to understand configuration objects (i.e. a single object with multiple optional or required properties as an argument to a function).
The official JSDoc syntax suggests that if a parameter is expected to have properties, you create a separate @param
line for each and use dot notation:
/**
* @param {Object} config
* @param {String} config.name
* @param {Number} config.gold
*/
function do_it(config) { ... }
However, Visual Studio doesn't recognize this - it renders config
, config.name
, and config.gold
as three separate top-level parameters.
Worse, the AutoComplete functionality within the method body doesn't recognize the parameters either, much less their types:
The only solution that appears to come even close in Visual Studio is to write never-called constructor functions with appropriate documentation (@constructor
and @property
tags), which makes me write a lot of dead code and also go against JavaScript's class-free mentality (which is the reason I use configuration objects in the first place). It doesn't even let me write the configuration object!
Not only that, but I also know that Visual Studio doesn't need it. For instance, when I wrote out a call to this library function, it was able to glean that the argument object needs properties called id
, source
, and target
, and suggested those names when I created an object literal for the function's argument - and without a single line of documentation. Presumably, it came from the simple fact that they were used:
Granted, the method does throw exceptions if these properties aren't on the object and aren't of the correct type, but still.
EDIT: And I recently was able to replicate the effect in my own code somewhat with object literal parameters - I called one function with a well-defined object, and it gave me Intellisense suggestions when I called the function again elsewhere in my code. But I still don't have type information or semantic access within the function body.
Visual Studio obviously understands the concept of configuration objects and is doing some logic to provide suggested properties. What is that algorithm? And how do I exploit it without mangling my code?
IntelliSense# Visual Studio Code's JavaScript IntelliSense provides intelligent code completion, parameter info, references search, and many other advanced language features.
You can trigger IntelliSense in any editor window by typing Ctrl+Space or by typing a trigger character (such as the dot character (.) in JavaScript). Tip: The suggestions widget supports CamelCase filtering, meaning you can type the letters which are upper cased in a method name to limit the suggestions.
You are using the correct JSDoc syntax, but as of today Visual Studio just doesn't build the right IntelliSense for parameter objects with named properties. There's currently no other way around this other than the one you refer to, but you can describe the config
object in place and avoid writing dead code as you mentioned like this:
/**
* @typedef {object} TestConfig
* @property {string} name
* @property {number} gold
*//**
* @param {TestConfig} config
*/
function test(config) {
}
Since we are only using this object for documentation and AutoComplete purposes we don't need to actually code it. This is not much more verbose than the original syntax and has the benefit of having the configuration object documented as well.
About your second question, the IntelliSense you can see for the sigma.js library is derived from parsing the body of the function code itself, not the JSDoc comments. That's why you can still use it when you add the minified "sigma.min.js" build to you project, where comments have been stripped.
You can test this adding parameter validation similar to the one in the library function (although accessing config.name
or config.gold
in any other manner will also yield the same result):
function do_it(config) {
if (Object(config) !== config || arguments.length !== 1) throw 'do_it: wrong arguments.';
if (typeof config.name !== 'string') throw 'config must have a name string field.';
if (typeof config.gold !== 'number') throw 'config must have a gold number field.';
...
}
Results in:
In a similar manner, once you provide enough information the correct type will be inferred:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With