Skip to content

JSDoc comment for destructuring param: description text not displayed #24746

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

Open
steph643 opened this issue Jun 7, 2018 · 25 comments
Open

JSDoc comment for destructuring param: description text not displayed #24746

steph643 opened this issue Jun 7, 2018 · 25 comments
Labels
Bug A bug in TypeScript Domain: JSDoc Relates to JSDoc parsing and type generation Help Wanted You can do this
Milestone

Comments

@steph643
Copy link

steph643 commented Jun 7, 2018

TypeScript Version:
2.9

Search Terms:
JSDoc destructuring param

Code

/**
 * @param {Object} arg
 * @param {number} arg.id - This param description won't show up
 */
function foo({ id }) {}

Expected behavior:
In VSCode 1.24.0, when typing foo(, IntelliSense should display the full param description, including its type and text.

Actual behavior:
The type is displayed ("number"), but not the text ("This param description won't show up"):
image

Related Issues:
#19645

Additional remark
When omitting the {Object} line, the param text shows up correctly:
image

@mhegazy mhegazy added Bug A bug in TypeScript Domain: JSDoc Relates to JSDoc parsing and type generation Help Wanted You can do this labels Jun 7, 2018
@mhegazy mhegazy added this to the Community milestone Jun 7, 2018
@mhegazy
Copy link
Contributor

mhegazy commented Jun 7, 2018

PRs welcomed.

@rbiggs
Copy link

rbiggs commented Jul 6, 2018

That's because TypeScript treats JSDoc types object and Object as any. You can designate a generic object using Object.<string, any>. So, redoing the above will give you the proper intellisense for id:

/**
 * @param {Object.<string, any>} arg
 * @param {number} arg.id - This param description will show up
 */
function foo({ id }) {}

// Intellisense for id will work
foo({id: 1})

@tannerbaum
Copy link

tannerbaum commented Sep 14, 2018

@rbiggs That does indeed work. However, VSCode only displays the description of the first parameter in the destructured object.

screen shot 2018-09-14 at 12 06 04

screen shot 2018-09-14 at 12 09 48

I feel like we are so close here!

@rbiggs
Copy link

rbiggs commented Sep 14, 2018

@THoisington, for that to work, you need to first define a custom object for the options, and then define its properties. Then you assign that custom type as your parameter:

/**
 * Entries Object.
 * @typedef {Object.<string, any>} requiredArguments
 * @property {string} timeSince
 * @property {string} timeUntil
 */
/**
 * 
 * @param {requiredArguments} param
 */
async function getEntries({timeSince, timeUntil}) {}

That'll give you IntelliSense for each property on the options parameter.

@tannerbaum
Copy link

tannerbaum commented Sep 17, 2018

This appears to have popped up in several issues, perhaps there could be some consolidation: #11597 and #11859, for example.

@rbiggs , I attempted your solution and found the vscode intellisense didn't display the subkeys or comments at all when using the @typedef and @property combination.

At the risk of making a huge comment, I will document my findings here.


Outcome 1: ❌ Top level details, ❌ subkey descriptions, ❌ current subkey highlighting.

screen shot 2018-09-17 at 16 28 17

screen shot 2018-09-17 at 16 29 27

JSDOC that caused this:

/**
 * @typedef {Object} requiredArguments
 * @property {string} timeSince Beginning date for the range...
 * @property {string} timeUntil End date for the range...
 */
/**
 * @param {requiredArguments}
 * @param {*} options - { filterUserId, filterCustomerId ... }
 * @see https://www.clockodo.com/en/api/entries/
 */
/**
 * @param {Object} requiredArguments
 * @param {string} requiredArguments.timeSince - Beginning date for the range...
 * @param {string} requiredArguments.timeUntil - End date for the range...
 * @param {Object} options { filterUserId, filterCustomerId ... }
 * @see https://www.clockodo.com/en/api/entries/
 */
/**
 * @typedef {Object.<string, any>} RequiredArguments
 * @property {string} RequiredArguments.timeSince - Beginning date for the range...
 * @property {string} RequiredArguments.timeUntil - End date for the range...
 */
/**
 * @param {RequiredArguments} params
 * @param {Object} options { filterUserId, filterCustomerId ... }
 */

Outcome 2: ✅ Top level details, ✅ subkey descriptions, ❌ current subkey highlighting.

screen shot 2018-09-17 at 16 33 29

screen shot 2018-09-17 at 16 33 46

JSDOC that caused this:

/**
 * @typedef {Object.<string, any>} RequiredArguments
 * @param {string} timeSince - Beginning date for the range...
 * @param {string} timeUntil - End date for the range...
 */
/**
 * @param {RequiredArguments} params
 * @param {Object} options { filterUserId, filterCustomerId ... }
 */
/**
 * @typedef {Object} RequiredArguments
 * @param {string} RequiredArguments.timeSince - Beginning date for the range...
 * @param {string} RequiredArguments.timeUntil - End date for the range...
 */
/**
 * @param {RequiredArguments} paramsss
 * @param {Object} options { filterUserId, filterCustomerId ... }
 */

I could move this comment to a different issue if it helps.

azu added a commit to asciidwango/js-primer that referenced this issue Dec 30, 2018
この書籍の主題ではないので、できるだけコンパクトな方法を採用

- microsoft/TypeScript#24045
- google/closure-compiler#1781
- microsoft/TypeScript#24746

fix #606
azu added a commit to asciidwango/js-primer that referenced this issue Dec 30, 2018
* fix(todo): JSDocのdestructuringの記法を修正

この書籍の主題ではないので、できるだけコンパクトな方法を採用

- microsoft/TypeScript#24045
- google/closure-compiler#1781
- microsoft/TypeScript#24746

fix #606

* fix(todo): removeEventListerを削除

TODOアプリのユースケースでは解除まで行っていないので削除する

fix #607

* feat(todo): 残った課題を追加

* chore(todo): add comment

* fix(todo): add <!-- doctest:disable -->
@sandersn
Copy link
Member

#11859 is just for Typescript, but is otherwise the same. Let's use this issue to track bugs in the Javascript side.

@lookuh
Copy link

lookuh commented Apr 7, 2020

Interestingly, both the typedef and the integrated properties syntax work if you declare the argument you're destructuring to be a @property instead of the @param that it is.

@jnfrati
Copy link

jnfrati commented Jan 13, 2021

I'm having the same issue, I'm currently using javascript, and the solution provided by @lookuh partially implemented works in an awkward way.

When used the JSDocs comments in this way, it for sure won't show the destructured params comments:

/**
 * @param {object} params
 * @param {stirng} params.id Some usefull id
 * @param {number} params.randomNumber Some randome number
 */

Captura de Pantalla 2021-01-13 a la(s) 11 33 41

But when at least one of the param is defined as property, it starts to show the other params comments correctly, but it does not give type to them:

Captura de Pantalla 2021-01-13 a la(s) 11 41 03

Captura de Pantalla 2021-01-13 a la(s) 11 42 56

And a full typedef with @Property solution isn't showing the destructured params:

/**
 * @typedef MyParams
 * @property {string} id Some usefull id
 * @property {number} randomNumber Some random number
 * @property {Date} someDate Just a date
 */


/**
 * @function useCustomHook
 * @param {MyParams} params
 */

Captura de Pantalla 2021-01-13 a la(s) 11 49 24

Hope this comment helps in any way.

@Juanpam
Copy link

Juanpam commented Sep 6, 2021

Just another workaround. I'm adding all the params as regular parameters instead and that way I get intellisense to display the properties in the argument as well as the description. It is also hinted that the function expects an object rather than multiple parameters:

image

/**
 * This function syncs the player configuration available in the server with the one sent by the player.
 * @param {object} argument
 * @param {string} playerID - ID of the player which configuration is going to be synced.
 * @param {Object} playerStatus - Object representing the status of the player.
 * @param {boolean} isTest - Indicate if this action is a test or not.
 * @param {Object} playerUpdates - Object representing the updates sent by the player.
 * @returns Resolves if the configs have been synced succesfully. Rejects otherwise.
 */

Only drawback is the additional parameter that is shown as well (argument param in this case).

@J3m5
Copy link

J3m5 commented Sep 7, 2021

@Juanpam The problem here is that we lose the type definition of the arguments at the top.
We can't have both at the same time.

@Juanpam
Copy link

Juanpam commented Sep 20, 2021

@J3m5 I agree! Just my workaround for this issue. Still hoping this gets reviewed soon.

@kolchurinvv
Copy link

having the same issue with in vscode in javascript using a named parameter
custom error class jsdoc

@ShadowLNC
Copy link

I seem to have the same issue but I am not specifying my types in JSDoc because I'm explicitly specifying them on the function, e.g.:

/**
 * Description.
 *
 * @param arg0 arguments.
 * @param arg0.a first.
 * @param arg0.b second.
 * @param arg0.c third.
 */
public async myFunc({a, b, c}: SomeInterface) {}

Apologies if this is not intended to be supported, the JSDoc docs only show examples where the types are in JSDoc (for object destructuring), but I know that VSCode does display the tooltip for regular parameters even when I don't put types in JSDoc.

@PoulBak
Copy link

PoulBak commented Aug 8, 2022

Is JSDoc dead? This is not solved after more than 4 years.

@joesawa
Copy link

joesawa commented Jan 26, 2023

Problem still persists into 2023.

@dagadbm
Copy link

dagadbm commented Jan 30, 2023

I have found the simplest cleanest solution for this mess.

/**
 * Main entrypoint and recommended function to use for route navigation.
 * @param {string} location - The path or url to navigate to, serves as a fallback url when goBack is true
 * @param {object} [config] - Additional configuration to alter the navigation
 * @property {object} [config]
 * @param {boolean} [config.replace] - If true, will use replace instead of push. This bypasses the browser history mechanism.
 * @param {boolean} [config.newTab] - If true, will open the url in a new tab, using window.open bypassing router
   * navigation.
 * @param {function} [config.callback] - If a function, will be called after navigation has ended
 * @param {boolean} [config.goBack] - If true, will use the browser history mechanism to go back. If going back leaves
 * the page, e.g. triggers beforeunload event, we warn the user, if he wants to stay in the page we redirect to the
 * provided url, which serves as a fallback.
 */

image

@kolchurinvv
Copy link

@dagadbm At least there's some work-around. It still doesn't seem to cut it for me, though. take a look:

export class ExtendedPromiseError extends Error {
  /**
   * `val: "default"` assigns `this.val = val(){return {}}`\
   * you can also assign any value to this prop
   *
   * @param {String} message - required by the parent `Error` class
   * @param {object} options - optional
   * @param {string} [options.cause] - specific reason
   * @param {string|any}  [options.val] - for cases when handler needs to return a value
   * @param {string} [options.once] - if attaching a listener is undesirable
   */
  constructor(message, options) {
    super(message)
    this.message = message
    this.name = "Extended Promise Error"
    this.cause = options?.cause
    if (options?.val) {
      if (options.val === "default") {
        this.val = () => {
          return {}
        }
      } else {
        this.val = options.val
      }
    }
  }
}

Screenshot 2023-01-30 at 13 55 40

is there a jsconfig.js / tsconfig.ts setting i'm missing/misusing?

@dagadbm
Copy link

dagadbm commented Jan 30, 2023

You are missing the empty line I added with the @Property part.

@kolchurinvv
Copy link

that was dumb of me 🤣 - worked like a charm! 💯

@joesawa
Copy link

joesawa commented Feb 2, 2023

I have found the simplest cleanest solution for this mess.

/**
 * Main entrypoint and recommended function to use for route navigation.
 * @param {string} location - The path or url to navigate to, serves as a fallback url when goBack is true
 * @param {object} [config] - Additional configuration to alter the navigation
 * @property {object} [config]
 * @param {boolean} [config.replace] - If true, will use replace instead of push. This bypasses the browser history mechanism.
 * @param {boolean} [config.newTab] - If true, will open the url in a new tab, using window.open bypassing router
   * navigation.
 * @param {function} [config.callback] - If a function, will be called after navigation has ended
 * @param {boolean} [config.goBack] - If true, will use the browser history mechanism to go back. If going back leaves
 * the page, e.g. triggers beforeunload event, we warn the user, if he wants to stay in the page we redirect to the
 * provided url, which serves as a fallback.
 */
image

Sadly this leaves out type information.

@dagadbm
Copy link

dagadbm commented Feb 2, 2023 via email

@woodjs
Copy link

woodjs commented May 1, 2023

My decision

/**
 * Middleware для загрузки файлов
 * @param {{
 *  allowedExtensions: string[];
 *  compress?: boolean;
 *  directory?: string;
 * }} options - Data Object
 * @param directory - Папка, в которую будут загружаться файлы (по умолчанию: uploads)
 * @param allowedExtensions - Расширения файлов, которые разрешены для загрузки (по умолчанию: ['jpg', 'jpeg', 'png', 'gif'])
 * @param compress - Сжимать ли файлы (по умолчанию: false)
 * @returns {function} - Middleware для загрузки файлов
 */

@dmrickey
Copy link

dmrickey commented Jun 22, 2023

This is still an issue. The official jsdoc gives this example

/**
 * Assign the project to an employee.
 * @param {Object} employee - The employee who is responsible for the project.
 * @param {string} employee.name - The name of the employee.
 * @param {string} employee.department - The employee's department.
 */
Project.prototype.assign = function({ name, department }) {
    // ...
};

Found here https://jsdoc.app/tags-param.html#parameters-with-properties
subheader - Documenting a destructuring parameter

I'd expect the tooltip to work if the jsdoc is correct per its own documentation

@jpc-ae
Copy link

jpc-ae commented Sep 26, 2023

I'm unsure if this could be related to the issue, but I noticed that semicolons are being added instead of commas to object parameters. This happens regardless of using the dot-notation or object definition syntax.

image

That is, both of the following result in the above tooltip:

/**
   * Space object stores snippet groupings in buckets.
   * @param {{name: string, synced: boolean, data: DataBucket}} params
   */
/**
   * Space object stores snippet groupings in buckets.
   * @param {Object} params
   * @param {string} params.name
   * @param {boolean} params.synced
   * @param {DataBucket} params.data
   */

I wasn't able to find where this semicolon is being added in the jsdoc parser, but could someone please fix that at least?

@Genroa
Copy link

Genroa commented Oct 13, 2023

Bumping up this. It's a major issue. Destructured parameters have been around since ES6, and JSDoc has an official documentation on how to document them properly. They're used everywhere, why was it never properly supported in VSCode's JSDoc tooltips?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: JSDoc Relates to JSDoc parsing and type generation Help Wanted You can do this
Projects
None yet
Development

No branches or pull requests