If I do like this I can desribe my property and get intellisense when later using myObject (using Visual Studio Code).
/**
* #type {MyObject}
*/
const myObject = object.nestedObject.myObject;
But what if I destruct an object like this
/**
* #type {MyObject}
* #type {MyObjectTwo}
*/
const { myObject, myObjectTwo } = object.nestedObject;
How can I use JSDoc to understand this way of assigning properties (deconstructing an object) so that I can get intellisense on myObject and myObjectTwo?
Related
I'm using the documentation package, but cannot figure out how to get it to document class properties (that aren't defined via getters and setters).
As the following just generates class documentation for SomeClass, but omits the someProperty documentation.
/**
* SomeClass is an example class for my question.
* #class
* #constructor
* #public
*/
class SomeClass {
constructor () {
this.someProperty = true // how do I document this?
}
/**
* someProperty is an example property that is set to `true`
* #property {boolean} someProperty
* #public
*/
}
An aside: the #constructor on the class jsdoc is a documentation thing.
Move the JSDoc for someProperty into the constructor where it is first defined:
/**
* SomeClass is an example class for my question.
* #class
* #constructor
* #public
*/
class SomeClass {
constructor () {
/**
* someProperty is an example property that is set to `true`
* #type {boolean}
* #public
*/
this.someProperty = true
}
}
I'm unsure if there is a way of accomplishing it with the documentation package using an approach that doesn't involve inlining the JSDocs into the constructor.
Another way is to declare them in class documentation as follows:
/**
* Class definition
* #property {type} propName - propriety description
* ...
*/
class ClassName {
constructor () {...}
...
}
You can declare properties in a class, and use #type to declare a type for them. Worked in VSCode 1.70.2 with in a plain ECMAScript Module.
class Foo {
/**
* Some bary data
* #type { BarClass }
*/
bar;
}
let f = new Foo();
f.bar; // Intellisense can tell you type and purpose
I'm trying to typecheck a library that returns an Object of constructor functions. With the following code Closure errors with:
./my-app.js:11: ERROR - Cannot call non-function type Foo.Wheel
const wheel = new Foo.Wheel();
^
Here's the code structure:
my-app-code.js - The code I'm using
const Foo = /** #type{!Foo.Module} */ require('foo');
const wheel = new Foo.Wheel();
wheel.rotate();
externs-foo.js - Closure externs for the Foo library
/** #const */
const Foo = {};
/** #record */
Foo.Module = function() {};
/** #type {!Foo.Wheel} */
Foo.Module.prototype.Wheel;
/** #constructor */
Foo.Wheel = function() {};
/**
* #returns {void}
*/
Foo.Wheel.prototype.rotate = function() {};
foo/index.js - corresponds to Foo.Module type.
module.exports = {
Wheel: require("./wheel"),
};
foo/wheel.js - corresponds to Foo.Wheel.
function Wheel() {}
Wheel.prototype.rotate = function() {};
module.exports = Wheel;
I tried one variation on externs-foo.js with the following results.
Make Foo.module.prototype.Wheel a function
/** #return {!Foo.Wheel} */
Foo.Module.prototype.Wheel = function() {};
Errors with:
my-app.js:11: ERROR - Expected a constructor but found type function(this:Foo.Module):Foo.Wheel.
const wheel = new Foo.Wheel();
my-app.js:13: ERROR - Property rotate never defined on module$myapp_Foo of type Foo.Module
wheel.rotate();
I'm aware of two solutions to this issue:
Declaring Foo.Module.prototype.Wheel = Foo.Wheel; in the externs file.
Use #type {function(new:Foo.Wheel)}, which says that the function is in fact a constructor that instantiates a Foo.Wheel object.
I prefer solution #1 because it declares a reference to the constructor function, so the compiler will allow me to access properties of the constructor (e.g. static methods). IIRC this can't be done in solution #2.
The annotations #type {!Foo.Wheel} and #return {!Foo.Wheel} won't work because they refer to an instance of Foo.Wheel and what you actually want is the constructor itself.
I have a CONST object that holds all my constants.
To set a constant, I have a function setConst(), that adds a new key to the CONST object, if it doesn't exist.
However, Webstorm can't track these variables. I'm trying to resolve it, by using jsDoc, but can't seem to find the right code. Here is what I have tried:
/**
* #name MY_CONST
* #param CONST.MY_CONST
* #type {String}
* #memberOf CONST
*/
setConst('MY_CONST', 'hello');
//Using MY_CONST here throws an Unresolved Variable in Webstorm
MyFunction.prototype[CONST.MY_CONST] = function() {...}
function setConst(key, value) {
if(CONST[key]) {
throw "Key " + key + " already exists in CONST";
}
CONST[key] = value;
}
Can you fix this with jsDoc? Or do I just have to accept the unresolved variable errors?
Found the right jsDoc combination - here it is:
/**
* #prop CONST.MY_CONST
* #type {String}
* #memberOf CONST
*/
In the following code I would like to define a shape of ApplicationSettings type using testSettings variable, so that inside useSettings function IDE would know which properties are accessible on the settings object:
/** #typedef ApplicationSettings */
var testSettings = {
apiService: {},
configuration: {}
};
/**
* #param {ApplicationSettings} settings
*/
function useSettings(settings) {
console.log(settings.apiService); // apiService is not recognized here
console.log(settings.configuration); // same for configuration
}
Unfortunately, seems that #typedef is not a valid annotation in that case. Is it possible to tell WebStorm how ApplicationSettings type should look like without explicitly specifying all of its properties in JSDoc?
Why do you need #typedef here? the following syntax works:
var testSettings = {
apiService: {},
configuration: {}
};
/**
* #param {testSettings} settings
*/
function useSettings(settings) {
console.log(settings.apiService);
console.log(settings.configuration);
I'm trying to expose the return type of a function where the return type is defined within the function's own scope.
// ==ClosureCompiler==
// #compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==
/** #return {MyType} */
function func(){
/** #constructor */
function MyType(){}
return new MyType();
}
/** #type {MyType} */
var instance = func();
When I compile this here, I get two type errors one for the #return annotation and one for the #type annotation. Both errors say Unknown type MyType. Is there a way to get this pattern to compile with type-checking?
Maybe it can't find the type because MyType as a type is not available when you create instance (can't do new MyType() or instance instanceof MyType).
This can be fixed by adding a typedef in the same scope as instance or create instance in the same scope as MyType.
Both:
/** #typedef {Object} */
var MyType;
/** #return {MyType} Returns new MyType **/
function func(){
/** #constructor */
function MyType(){
}
return new MyType();
}
/** #type {MyType} */
var instance = func();
and:
function func(){
/** #constructor */
function MyType(){
}
/** #type {MyType} */
var instance = new MyType();
return new MyType();
}
Won't produce any warning
[update]
To provide a complex type through annotation is going to be painfully hard. You can make the type as complex as you want. Using externs would not work because externs variables and their functions won't be renamed to shorter names (without some extra compile parameters) and you can't re define the type. So I guess you're basically stuck with providing a typedef annotation:
/** #typedef {{hands:number,doSomething:function(string):boolean}} */
var MyType;
/** #return {MyType} Returns new MyType **/
function func(){
/** #constructor */
function MyType(){
this.hands=22;
}
MyType.prototype.doSomething=function(msg){
return true;
}
return new MyType();
}
/** #type {MyType} */
var instance = func();
/** #type string */
var myString=instance.hands;//warning:found number required string
/** #type Array */
var myArray=instance.doSomething("hi");//found boolean required Array
instance.doSomething(22);//found number required string
instance.doSomething();//at leas 1 argument(s)
The problem is that "MyType" is scoped with "func" and is not available outside. You might do better to define an #interface in the global scope and just use that type outside the defining function.