25

I'm writing JavaScript (ES6) code in Visual Studio Code and enabled VSCode's type checking as explained in the VSCode docs.

When referring to a type that is defined in another file (Track in the example below), I get an error like [js] Cannot find name 'Track' at the JSDoc reference to that type unless I import it. When I import this type, I get an error from ESLint: [eslint] 'Track' is defined but never used. (no-unused-vars)

I don't want to disable the ESLint rule. Is there a way to import the type only for the type checks in VSCode?

import Track from "./Track";

export default class TrackList {

/**
 * Creates a new track list.
 * @param {Iterable<Track>} tracks the tracks to include
 */
constructor(tracks) {
    this._tracks = tracks ? Array.from(tracks) : [];
}
...
4
  • Have you tried to add Track to the globals in ESLint config? Commented Dec 26, 2017 at 11:10
  • Or disable rules with comments in ESLint Commented Dec 26, 2017 at 11:15
  • @Alex Adding Track to globals does not help. JSDoc needs a reference to the source code. Disabling rules would help, but I don't like to disable the rule entirely as this would limit the use of ESLint. Disabling it only for certain names works via the varsignorepattern option but using this pattern in every other file would be rather ugly. Commented Dec 26, 2017 at 13:25
  • @ralfstx did you try Alex's link to the comment syntax to disable rules for a specific line or section? I had trouble getting the single-line versions to work but I was able to use a disable comment, then import, then an enable comment, and I get the best of both worlds -- eslint checks everything else, and Intellisense uses the correct type information. Commented May 10, 2018 at 8:44

4 Answers 4

19

I have a similar problem and here is how I solved it.

//file.d.ts
export interface Foo {
    bar: number;
}

export as namespace Baz;

Doing this will make the Baz namespace global so you can use it anywhere without importing

/**
 * @param {Baz.Foo} arg 
 */
function test(arg) {

}

Now you get intellisense and type checking in VSCode.
VS Code

Sign up to request clarification or add additional context in comments.

1 Comment

I find this answer fascinating, thank you for that. This way we can keep types in a single d.ts file and "import" them across the codebase within JSDoc without actually having to write "import" everywhere. What's not to like?
8

You can use import("%YOUR_LIB%").%TYPE%:

export default class TrackList {

/**
 * Creates a new track list.
 * @param {Iterable<import("./Track").Track>} tracks the tracks to include
 */
constructor(tracks) {
    this._tracks = tracks ? Array.from(tracks) : [];
}
...

Since Track is exported as default, you could also use:

/** @param {Iterable<import("./Track").default>}

Or as Tiago pointed out:

/** @typedef { import('./Track').default } Track */

/**
 * Creates a new track list.
 * @param {Iterable<Track>} tracks the tracks to include
 */
...

2 Comments

Perfect... and hideous. ;^) How in the world did you come across that?
I've got this hint from some IDE dev. team, when I've opened a ticket that code completion works not as expected.
6

Just to keep this topic updated:

With [email protected] you will be able to import JSDoc typedefs, that are automatically exported.

Take a look at this issue with a real working example. Also you can walk along webpack's code to see how they used JSDoc and typescript to statically chech their pure JS sourcecode base. here is their issue with JSDoc conventions where you can get insipration.

1 Comment

To make it easier, applying this answer to your case it would mean adding /** @typedef { import('./Track').default } Track */
1

The workaround to disable es-lint warning: using //eslint-disable-line no-unused-vars comment in the end of line with unused import.

import Track from './Track'; //eslint-disable-line no-unused-vars

export default class TrackList {

/**
 * Creates a new track list.
 * @param {Iterable<Track>} tracks the tracks to include
 */
constructor(tracks) {
  this._tracks = tracks ? Array.from(tracks) : [];
}
...

1 Comment

Except the import was only shown to get around the problem of linting going "I have no idea what Track is". By actually writing import code, there is suddenly a code dependency between the two files, instead of only a typing dependency. This file will now cause the JS engine to run the module that Track lives in, even though it shouldn't.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.