question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

JSDoc equivalent of import *

See original GitHub issue

Search Terms

  • jsdoc import
  • import *
  • import namespace
  • jsdoc namespace

Suggestion

Provide a JSDoc equivalent of import * as Sub from "./sub" so that types & interfaces from the ./sub module could be referenced as Sub.Type, Sub.Interface.

I have no preference in terms of actual syntax, but in my experience general expectation had been that following syntax should do just that (but it is not and I can’t seem to figure out what does Sub results in here:

@typedef {import('./sub')} Sub

If above is not a viable options maybe using same * character could be an options:

@typedef {import('./sub').*} Sub

Or maybe whole new @import jsdoc tag.

Use Cases

js-ipfs (fairly large code base) has adopted TS via JSDoc syntax but dealing with large number of imported types & interfaces from other modules had been a major source of pain for following reasons:

  1. Every single type requires @typedef {import('...').Name} Alias.
  2. Importing generic types / interfaces requires repeating type parameters via @template tags
  • Which is error prone because when omitted it turns into any
  • Ends up require lot of typing
  1. Changes to library layout requires updating all those typdefs all over the code base (and vscode can’t help there sadly)
    • Alternative is to consolidating them in one place, but then vscode (and alike) takes multiple hops / clicks to get you to actual type definition.

All of the above make otherwise mostly good experience to be painful.

Current approach also has side effect of turning imported interfaces into types (see #41258) which than can’t be used in implements syntax as they are no longer interfaces.

Given that it is possible to do import * as Sub from "./sub" to get a namespace of exports in TS syntax it seems like equivalent in jsdoc syntax would:

  1. Allow reduced number of @typedef {import(...).Name} Name declarations.
  2. Allow importing generic types without having to retype type parameters via @temaplate tags.
  3. Avoid turning interfaces.

Examples

Consider following TS code:

import { BlockEncoder, BlockDecoder } from "@multiformats/codecs"
import { DagNode } form "./node"

class DagPB implements BlockEncoder<0x70, DagNode>, BlockDecoder<0x70, DagNode> {
  async encode(node:DagNode):Promise<Uint8Array> {
     // ...
  }
  async decode(bytes:Uint8Array):Promise<DagNode> {
    // ...
  }
}

Same code with JSDoc syntax turns into following:

/**
 * @template {number} Code
 * @template T
 * @typedef {import('@multiformats/codecs').BlockEncoder<Code, T>} BlockEncoder
 */
/**
 * @template {number} Code
 * @template T
 * @typedef {import('@multiformats/codecs').BlockDecoder<Code, T>} BlockDecoder
 */
/**
  * @typedef {import("./node").DagNode} DagNode
  */

/**
 * @implements {BlockEncoder<0x70, DagNode>}
 * @implements {BlockDecoder<0x70, DagNode>}
 */
class DagPB {
  /**
   * @param {DagNode} node
   * @returns {Promise<Uint8Array>}
   */
  async encode(node) {
     // ...
  }
  /**
   * @param {Uint8Array} bytes
   * @returns {Promise<DagNode>}
   */
  async decode(bytes) {
    // ...
  }
}

Note: Above code won’t even produce desired typedefs due to #41258

And now if we had what this issue proposes it would be:

/**
 * @typedef {import('@multiformats/codecs')} Codec
 * @typedef {import('./node').DagNode} DagNode
 */

/**
 * @implements {Codec.BlockEncoder<0x70, DagNode>}
 * @implements {Codec.BlockDecoder<0x70, DagNode>}
 */
class DagPB {
  /**
   * @param {DagNode} node
   * @returns {Promise<Uint8Array>}
   */
  async encode(node) {
     // ...
  }
  /**
   * @param {Uint8Array} bytes
   * @returns {Promise<DagNode>}
   */
  async decode(bytes) {
    // ...
  }
}

Checklist

My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript/JavaScript code
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:16
  • Comments:9 (1 by maintainers)

github_iconTop GitHub Comments

5reactions
Jamesernatorcommented, Sep 23, 2021

Just to clarify what the issue actually is, essentially this:

/**
  * @typedef {import("./someModule.js")} SomeModule
  */

is actually equivalent to this:

/**
  * @typedef {typeof import("./someModule.js")} SomeModule
  */

In TypeScript however the following are distinct in general:

import type * as SomeModule from "./someModule.js";
type SomeModule = typeof import("./someModule.js");
4reactions
Gozalacommented, Feb 25, 2022

@RyanCavanaugh @sandersn any updates on this ? This is probably the most annoying limitation when using TS with JSDoc.

If someone is willing to mentor me on this, I’d be up to put my time into this.

Read more comments on GitHub >

github_iconTop Results From Across the Web

JSDoc Reference - TypeScript: Documentation
You can import declarations from other files using import types. This syntax is TypeScript-specific and differs from the JSDoc standard:.
Read more >
JSDoc import(" ... ") does not work with ES6 modules
I use following pattern to get a refference to a symbol for JSDoc, without really including it in a document: ``` /** *...
Read more >
How to "import" a typedef from one file to another in JSDoc ...
Import the declared type in your file File2.js using the function import . const persons = require('./File1.js'); /** * @typedef {import('.
Read more >
Support TypeScript import()-types in JSDoc : WEB-31971
Furthermore, very few modules have proper JSDoc's for modules/namespaces and IDE often gets confused with namespace collisions. TypeScript approach is better, ...
Read more >
Use JSDoc: @module
The @module tag marks the current file as being its own module. All symbols in the file are assumed to be members of...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found