Skip to content

JSDoc equivalent of import *  #41825

Closed
@Gozala

Description

@Gozala

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions