Right now I couldn't find a way to document that a function argument (a property, or anything really) is a class, or a constructor of a specific type.
Here's a condensed example of the problem:
class View {}
class SomeView extends View {}
/* *
* This is a factory function that instantiates a new view object
* from the given View class and the given data.
*
* @param {???} ViewClass a constructor/class that extends View
* @param {*} [data]
* @return View a new View instance
* */
function createView(ViewClass, data) {
return new ViewClass(data)
}
var something = createView(SomeView, {});
How is it possible to tell that the type of ViewClass is a constructor/class and that it extends View?
What should go in the place of the question marks up there?
@param {View} thing this means that thing is a View instance, not a class
@param {Function<View>} thing this doesn't really mean that thing is a class that extends View
@param {typeof View} thing logically this is what we're looking for, but frankly I've never seen this one used before, not in the docs at least
Is Function<View> currently the only one acceptable?
In VSCode, the assignment works (passing a constructor/class to a function expecting a Function<SuperClassType>) but the new is flagged with
[js] Cannot use 'new' with an expression whose type lacks a call or construct signature.
This is keeping me from using VSCode's static type checking :frowning_face:
Closure Compiler has a syntax for this: https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#function-new-type
And TypeScript / VS Code even understands it.
I'm using jsdoc together with typescript since it let's me to write plain old javascript and do the typechecking against the jsdoc. The syntax:
@property {typeof SomeClass} SomeClass
seems to be working fine in that environment. In my case (and i think is a very common case) I'm documenting what a native library provides. The module is exporting an object which properties are classes so this was mandatory. Unfortunately this is not valid jsdoc code and I dont have a way to exclude some comments from the jsdoc parser :(
I think this is very very important
Have you tried the {function(new:SomeClass)} syntax from @thorn0 's link? Also, have you considered moving your module declarations out to a .d.ts file instead? I prefer documenting JS inline where possible, but in your case it might be more flexible to describe the native library in actual Typescript.
@thw0rted that would work only in the case that I do new SomeClass but not in the case I want to call static methods / static members (example below). What we really needs is typeof that BTW is supported by typescript although not documented. I'M WRITING A JSDOC PLUGIN TO CHANGE {typeof A} to {A} or to {Class<A>} so at least jsdoc won't fail but IMO this should be solved in jsdoc without plugins. FWI, I already implemented a plugin for preventing some comments to be parsed by jsdoc (https://github.com/cancerberoSgx/jsdoc-prevent-comment-parse-plugin) so I'm not blocked anymore, but I really want this information to be exported in the docs so I need this other plugin. Will let you know when done.
Example of static methods in which {function(new:SomeClass)} wont work:
/**@class */
class SomeClass(){
/**
* Extends the current component to generate a child one
* @param {*} componentDefinition Any object with properties/methods that will be used to generate the Component that will be returned
* @return {*}
* @static
*/
static extend(componentDefinition) {
return null
}
}
.....
/**
@param {function(new:SomeClass)} Class
@return {*}
*/
function userCodeDONTwork(Class){
return Class.extend({foo: 1})
}
/**
@param {typeof SomeClass} Class
@return {*}
*/
function userCodeWorks(Class){
return Class.extend({foo: 1})
}
Done ! :) https://github.com/cancerberoSgx/jsdoc-typeof-plugin ... Now I can have types that refer classes, something very very basic that jsdoc should support.
This feature is highly missed. At my company, we use the convention Class.<A> to document constructors. This helps conveying the right information on the documentation, but is not recognized by tools.
Using the proposed typeof A works for IntelliJ (https://youtrack.jetbrains.com/issue/WEB-17325) but, unfortunately, causes _eslint_ to start failing doclet parsing...
@dcleao in my team we also started using Class
+1 for typeof. In my case, I'm also interested in a future/Typescript-compatible way for pointing to an argument supporting a @callback signature or a specific method of an @interface (and I am not yet clear on whether Typescript supports this).
+1 for @param {typeof Foo} as per typescript & closer compiler. Not being able to specify a type of constructor / class and reference it's static methods is kind of a show-stopper for me right now. I'd love to see any solution that keeps both the closure compiler and JSDoc happy.
I think today TypeScript is the defacto "jsdoc" standard. Great part of jsdoc grammar is currently defined in the language itself and new jsdoc grammar for type-related things like this too.
Since is a formal grammar definition, IMO people will tend to move away from this project's grammar, particularly for type related semantics.
The TypeScript AST for
/**
* @returns {typeof C}
*/
function f(){}
is something like this - sorry for the indentation
FunctionDeclaration
JSDocComment
JSDocReturnTag
Identifier
JSDocTypeExpression
OpenBraceToken
TypeQuery
TypeOfKeyword <----- the same node kind than in actual typescript code
Identifier <----- this is the name of a class or typedef
CloseBraceToken
FunctionKeyword
Since the objective of TypeScript is typecheck, they needed to create that syntax and used the same grammar that's already present in TypeScript for that. In other situations they use syntax already in TS for jsdocs, for example, generics - they don't support @template but the well known syntax {Array
On the other hand TS syntax don't support documentation-related semantic like @link, @example, etc.
My point is, for those who want typechecking and already have jsdocs comments, give TypeScript a try. No modifications are needed in a js project, can be done gradually mixing js and ts files, and compilation / Type errors can be configured pretty flexible. Also jsdocs itself ends up being simpler since in TS, jsdocs don't have types references or to explain what's you are documenting @class @method are no needed. That simplify the comments a lot.
I wonder if there are any plans in this project to catch up or support more of current TypeScript jsdocs syntax.
An interesting proiect could be parse js code using TypeScript compiler and generate a AST compatible with the syntax of this project (so I can use themes, etc to document TS/JS projects).
Any updates on this?
how to add restrictions like i am waiting for classes that extends certain other classes?
for example, my function accepts class parameter that extends B:
/** @param {any extends B} */
function foo(ClassName) {}
Most helpful comment
This feature is highly missed. At my company, we use the convention
Class.<A>to document constructors. This helps conveying the right information on the documentation, but is not recognized by tools.Using the proposed
typeof Aworks for IntelliJ (https://youtrack.jetbrains.com/issue/WEB-17325) but, unfortunately, causes _eslint_ to start failing doclet parsing...