Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Salsa] Support jsdoc @namespace #14233

Open
mhegazy opened this issue Feb 22, 2017 · 12 comments
Open

[Salsa] Support jsdoc @namespace #14233

mhegazy opened this issue Feb 22, 2017 · 12 comments
Labels
Committed The team has roadmapped this issue Domain: JavaScript The issue relates to JavaScript specifically Domain: JSDoc Relates to JSDoc parsing and type generation Suggestion An idea for TypeScript
Milestone

Comments

@mhegazy
Copy link
Contributor

mhegazy commented Feb 22, 2017

Support treating variable declarations with @namespace JSDoc tag as TS namespaces.

/** @namespace */
var Documents = {
    /**
     * An ordinary newspaper.
     */
    Newspaper: 1,
    /**
     * My diary.
     * @private
     */
    Diary: 2
};
@mhegazy mhegazy added Domain: JSDoc Relates to JSDoc parsing and type generation Salsa Suggestion An idea for TypeScript labels Feb 22, 2017
@OliverJAsh
Copy link
Contributor

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()
}

@mhegazy
Copy link
Contributor Author

mhegazy commented Nov 28, 2017

would be subsumed by a fix for #16489

@mhegazy mhegazy added this to the TypeScript 2.7 milestone Nov 28, 2017
@mhegazy mhegazy modified the milestones: TypeScript 2.7, TypeScript 2.8 Jan 9, 2018
@mhegazy mhegazy modified the milestones: TypeScript 2.8, TypeScript 2.9 Mar 9, 2018
@que-etc
Copy link

que-etc commented Apr 20, 2018

@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.

@mhegazy
Copy link
Contributor Author

mhegazy commented Apr 20, 2018

you can just use:

// @filename: usage.js

/** @typedef {import('./interfaces').Foo} Foo */

/** @type {Foo} */
let foo;

@mhegazy mhegazy removed this from the TypeScript 2.9 milestone May 8, 2018
@RyanCavanaugh RyanCavanaugh added the Committed The team has roadmapped this issue label Aug 15, 2018
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 3.2 milestone Aug 15, 2018
@PavelPolyakov
Copy link

@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.

@weswigham weswigham added Domain: JavaScript The issue relates to JavaScript specifically and removed Salsa labels Nov 29, 2018
@sandersn sandersn modified the milestones: TypeScript 3.4.0, Backlog Mar 12, 2019
@noinkling
Copy link

noinkling commented Apr 3, 2019

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

@brendanarnold
Copy link

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.

@JHawkley
Copy link

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.

@leecjson
Copy link

SO, what's the news?

@kauesedrez
Copy link

kauesedrez commented Sep 19, 2020

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?

@callionica
Copy link

Just here to say that I expected the following to work in a Javascript file and it didn't work:

/** @namespace {import("vscode")} vscode */

/** @type {vscode.TextDocument} */

as a not very obvious workaround, I used

/** @type {import("vscode").TextDocument} */

instead.

It would be good if the first version using @namespace worked.

@finnmerlett
Copy link

This seems like an absolute no-brainer. Without it, I have to typdef-alias each individual type I want to use at the top of the file like

/** @typedef {import("@googlemaps/google-maps-services-js").DistanceMatrixRequest} DistanceMatrixRequest */

This both looks very messy, is overly verbose (I have to repeat the module names so many times) and forces me to disable my comment-length reflow ESLint plugin!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Committed The team has roadmapped this issue Domain: JavaScript The issue relates to JavaScript specifically Domain: JSDoc Relates to JSDoc parsing and type generation Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests