Rico Kahler
Rico Kahler

Reputation: 19202

How do I refer to another typescript type in comments/JSDoc?

I'm familiar with Javadoc. In Javadoc, you can place a link that refers to the Javadoc placed on another type like so:

/**
 * some java thingy. see this other java thingy too {@link OtherThingy}
 */
public class Thingy { /*...*/ }

/**
 * some other java thingy. see the first java thingy too {@link Thingy}
 */
public class OtherThingy{ /*...*/ }

Can I do the same in typescript's flavor of JSDoc? I know that I can use markdown in the comments and I can place web links but that's not exactly what I'm going for.

Also, any references to JSDoc/typescript documentation tools would be very helpful :)

Edit: Per the answers below, this is a feature of JSDoc but doesn't seem to be included in VSCode. Is there an valid syntax in VSCode?

Upvotes: 68

Views: 43624

Answers (3)

VonC
VonC

Reputation: 1323363

Yes, you can use @link

You can use {@link OtherThingy} in docs, and it works in VS Code since 2021. If you want an inline reference, just use that.

Details and alternatives

With VSCode 1.52 (Nov. 2020), you might also consider another tag:

Initial support for JSDoc @see tags

JSDoc @see tags let you reference other functions and classes in your JSDoc comments.

The example below shows crash function referencing the WrappedError class from another file:

// @filename: somewhere.ts
export class WrappedError extends Error { ... }

// @filename: ace.ts
import { WrappedError } from './somewhere'

/**
* @see {WrappedError}
*/
function crash(kind) {
   throw new WrappedError(kind);
}

VS Code will now include basic @see references while performing renames.

You can also run go to definition on the @see tag's content and @see tags will also show up in the list of references.

We plan to continue improving support for @see tags in future releases.

As Mark notes in the comments:

JSDoc @link support

We now support JSDoc @link tags in JavaScript and TypeScript comments.

These let you create clickable links to a symbol in your documentation:

Navigating code using JSDoc @link tags

JSDoc @link tags are written as: {@link symbolName}.

You can also optionally specify text to be render in place of the symbol name: {@link class.property Alt text}.

@link is supported in hovers, suggestions, and signature help.
We have also updated vscode.d.ts to use @link.


Note: cachius adds in the comments:

import { MyClassName } from "path/to/MyClassName";

If MyClassName is not already imported, adding @see MyClassName in the JSDoc would only show any on hover and doesn't allow ctrl + clickthrough to declaration/usages.

Importing it allows that, even if the only mention is in the JSDoc.
This is useful when a module/class refers to some other logically, but without using it directly.

Unused imports might trigger eslint warnings though, which I'd silence in this case with:

// eslint-disable-next-line @typescript-eslint/no-unused-vars 

To that effect, Daniel Steigerwald adds in the comments

The imported type must be actually used.
Otherwise, JSDoc will not process.

And:

Another more serious issue is that destructuring removes any JSDoc part containing @, making it effectively useless. That's why I have to replace all @example with Markdown, e.g. ### Example ts ...


Eric Haynes adds in the comments:

Consider using instead:

import type { MyClassName } from 'path/to/MyClassName';  

The type import will be elided at compile time, rather than adding an actual import in the compiled JavaScript.
(or import { type MyClassName, OtherThing } if you already have an import for something else on that path)


This seems to be the correct solution using import { type Foo }.
However, I get no-unused-vars eslint errors on the import, although it doesn't give me the typescript Foo is declared but its value is never read. warning.
Is there a way around this or is it an eslint bug?

While TypeScript understands that the import is used for type information and will remove it in the transpiled JavaScript (hence no TypeScript error), ESLint's default rules do not recognize type-only imports as being "used". Consequently, ESLint reports them as unused variables.

You can try and adjust your ESLint configuration to ignore unused vars that are only imported for types. That can be done by modifying the no-unused-vars rule in your .eslintrc configuration file, specifically using the ignoreRestSiblings and argsIgnorePattern options to exclude type imports:

{
  "rules": {
    "no-unused-vars": ["error", { "ignoreRestSiblings": true, "argsIgnorePattern": "^_" }],
    "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
  }
}

But that involves "tweaking" to specifically target type imports without inadvertently ignoring genuinely unused variables.

Another approach is to use the eslint-plugin-import plugin, which provides more granular control over import-related linting issues. That plugin includes a rule import/no-unused-modules, which can be configured to allow type-only imports. Make sure to install the plugin and configure it in your .eslintrc:

{
  "plugins": ["import"],
  "rules": {
    "import/no-unused-modules": [1, { "ignoreExports": ["path/to/your/typescript/files/**/*.ts"] }]
  }
}

You would specify paths and patterns that match your project's structure: it is more work upfront, but can lead to more precise control over linting behaviors.

If the issue only occurs in a few places and you prefer not to adjust global ESLint settings, you can disable the ESLint rule inline for specific imports:

// eslint-disable-next-line no-unused-vars
import { type Foo } from './foo';

If you are using the @typescript-eslint plugin (which is recommended for TypeScript projects), it provides a more TypeScript-aware version of the no-unused-vars rule. Make sure your ESLint is configured to use this rule instead of the base ESLint version:

{
  "extends": [
    "plugin:@typescript-eslint/recommended"
  ],
  "rules": {
    "no-unused-vars": "off", // Turn off ESLint's version
    "@typescript-eslint/no-unused-vars": ["error"] // Use TypeScript ESLint version
  }
}

That rule is better at understanding TypeScript's type-only imports and should not flag them as unused.

Upvotes: 41

Graham P Heath
Graham P Heath

Reputation: 7389

You sure can, though your mileage may vary.

1: A use of @link in Selenium-Webdriver's TypeScript typing file

/**
 * Converts a level name or value to a {@link logging.Level} value.
 * If the name/value is not recognized, {@link logging.Level.ALL}
 * will be returned.
 * @param {(number|string)} nameOrValue The log level name, or value, to
 *     convert .
 * @return {!logging.Level} The converted level.
 */
function getLevel(nameOrValue: string | number): Level;

2: Docs about @link in JSDoc

The following example shows all of the ways to provide link text for the {@link} tag: Providing link text

/**
 * See {@link MyClass} and [MyClass's foo property]{@link MyClass#foo}.
 * Also, check out {@link http://www.google.com|Google} and
 * {@link https://github.com GitHub}.
 */
function myFunction() {}

By default, the example above produces output similar to the following: Output for {@link} tags

See <a href="MyClass.html">MyClass</a> and <a 
href="MyClass.html#foo">MyClass's foo
property</a>. Also, check out <a 
href="http://www.google.com">Google</a> and
<a href="https://github.com">GitHub</a>.

Upvotes: 43

vaindil
vaindil

Reputation: 7846

VS Code treats {@link} as a comment, so it doesn't get any special parsing (it's just displayed exactly as you typed it). There's currently an open issue to fix this, however.

Upvotes: 15

Related Questions