Support treating variable declarations with @namespace JSDoc tag as TS namespaces.
/** @namespace */
var Documents = {
/**
* An ordinary newspaper.
*/
Newspaper: 1,
/**
* My diary.
* @private
*/
Diary: 2
};
Is there any workaround for this? I want to use my object at the type level. I tried using typeof but it seems that doesn't work with JSDoc:
{
class Foo {}
const X = { Foo }
// line below errors with "Cannot find name 'typeof'"
/** @type {typeof X.Foo} */
const foo = new X.Foo()
}
would be subsumed by a fix for https://github.com/Microsoft/TypeScript/issues/16489
@mhegazy
After this one gets merged, would it be possible to use the import() statement to import all types of a module?
// @filename: interfaces.d.ts
export interface Foo {}
// @filename: usage.js
/** @namespace {import('./interfaces')} NS */
/** @type {NS.Foo} */
let foo;
Seems that @typedef can't be used for it, which is no surprise, of course.
you can just use:
// @filename: usage.js
/** @typedef {import('./interfaces').Foo} Foo */
/** @type {Foo} */
let foo;
@mhegazy
I know we're in the TypeScript repository, but the issue topic is jsdoc.
vscode supports types import via the code from your example, but this code can not be processed with jsdoc itself.
[~/Projects/tmp/jsdoc-example]$ jsdoc ./ *[master]
ERROR: Unable to parse a tag's type expression for source file /Users/pp/Projects/tmp/jsdoc-example/executor.js in line 1 with tag title "typedef" and text "{import('./my-new-type')} MyNewType": Invalid type expression "import('./my-new-type')": Expected "!", "=", "?", "[]", "|" or end of input but "(" found.
What can I do with this?
In my situation I have a type declaration in the file A and want to import it in the file B. But I still want things to be jsdoc compatible.
This is really just expanding on @que-etc's comment:
Currently there doesn't seem to be a way to alias namespaces in JSDoc like you can do with a TS import ... = ... declaration.
I can use @typedef with a namespace path to alias/shorten the reference to a type, e.g:
/** @typedef {lib.data.persistence.MyType} MyType */
But I can't do the same with a namespace because it's not a type:
/** @typedef {lib.data.persistence} types */
Namespace 'global.lib.data' has no exported member 'persistence'. ts(2694)
Or if it does happen to be a type too, its namespace meaning isn't recognized in subsequent paths:
/** @type {types.MyType} */
let someVar;
'types' only refers to a type, but is being used as a namespace here. ts(2702)
If I have a whole bunch of types from that namespace that I want to use, I have to qualify them with the whole path every time, or go through and alias them one by one. It's the same issue with import(), which tends to be pretty verbose and not so nice to look at.
I would very much like to be able to do:
/** @namespace {lib.data.persistence} types */
/** @namespace {import('../../../lib/data').persistence} types */
or something along those lines. Maybe using the @import tag instead for parity with TS syntax? I guess this overlaps with #22160
My project is a vanilla Javascript project and we use JSDocs for documentation and to enable some degree of type checking in VSCode and for JSDoc code generation.
Webstorm supports the standard @memberOf tag and @namespace but not the non-standard (i.e. TypeScript specific) import() syntax, same with the JSDoc tooling. VSCode does the opposite.
This is very annoying for the project team, half of which use VSCode and half use WebStorm.
Dealing with JSDoc @typedef type-aliases that use a @template tag has been a real thorn in my side. Generic-like types cannot be imported using the import() type without either specifying the type parameters or duplicating them with new @template tags.
Which is weird, and I guess that is how JSDoc handles these types? ...but it is still strange you cannot simply reference a generic type in a @typedef without making it concrete.
Taking advantage of JSDoc's virtual namespaces could alleviate this problem, allowing you to specify your aliases as a member of a virtual namespace, then import the namespace, reference the generic type, and provide the type parameters when and where you need them.
Funny enough, TypeScript does support virtual namespaces within the same file by simply creating a @typedef with a name that is prefixed with a namespace path; a @namespace tag never needs to be provided to define the namespace.
// File: ./types.js
/**
* @template T
* @typedef {T | Promise.<T>} Aliases.MaybePromise
*/
// This checks correctly...
/** @typedef {Aliases.MaybePromise.<string>} MaybePromisedString */
However, TypeScript does not export these top-level virtual namespaces as it does with other @typedef type-aliases.
// File: ./elsewhere.js
// This fails with a "...has no exported member 'Aliases'" error.
/** @typedef {import("./types").Aliases} Aliases */
// Naturally, since the import failed, this fails to check.
/** @typedef {Aliases.MaybePromise.<string>} MaybePromisedString */
I think supporting, at a minimum, a @namespace alias to access the types provided by a module would solve a lot of issues when it comes to TypeScript-supported type-checking in the JavaScript domain, especially when it comes to importing types from other modules, letting us get at types in a module without constantly repeating @typedef {import("...").T} T for each desired type and having to duplicate the @template tags for generic types.
One potential idea to consider is to utilize JSDoc namepaths and treat a module referenced with the import() type as a virtual JSDoc namespace, where real members exported by the module are treated as instance # members of the JSDoc namespace while top-level virtual types created with @typedef, @callback, and @namespace are treated as static . members.
But implementing this would be a breaking change in JSDoc support. Right now, the import() type is currently treated as the entanglement of both a typeof type and a namespace until you reference either an exported member or virtual type and collapse the wave function. 馃槢
Using namepaths to disambiguate between the two cases seems more like the JSDoc way, but the import() type is still non-standard and that is a problem all its own.
SO, what's the news?
The problem persists
jsdoc -d docs ./Routes/index.js
ERROR: Unable to parse a tag's type expression for source file /home/kaue/myApp/Routes/index.js in line 1 with tag title "namespace" and text "{ import('express').Application } Express": Invalid type expression "import('express').Application": Expected "!", "=", "?", "[]", "|", or end of input but "(" found.
My code
/**
* @typedef { import('express').Application } Express
* @param {Express} app
*/
Any update guys?
Most helpful comment
@mhegazy
After this one gets merged, would it be possible to use the
import()statement to import all types of a module?Seems that
@typedefcan't be used for it, which is no surprise, of course.