Skip to content
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

TypeScript / JavaScript - IntelliSense - Improve JSDoc display for overloaded functions, including ones overloaded with @overload #55056

Open
aweebit opened this issue Jul 12, 2023 · 0 comments
Labels
Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript
Milestone

Comments

@aweebit
Copy link

aweebit commented Jul 12, 2023

  • Currently, JSDoc is only correctly displayed when hovering over an overloaded function definition if the function is a class method and overloaded using TypeScript declarations. In such cases, the description from the JSDoc of the function definition is shown when hovering over the function overloads if no own overload description is provided, which is pretty awesome because one does not have to copy the description to the docs of each overload if it is the same for all of them. I would definitely want it to work this way for all overloaded functions,
  • However, if the function is defined and the overloads declared with the function keyword, no description is borrowed from the definition when displaying JSDoc information for the overloads. And when hovering over the function definition, the JSDoc of the first overload is displayed.
  • And if the function is overloaded with the TypeScript-flavored JSDoc @overload tag, no JSDoc information is displayed whatsoever despite the overloads clearly being recognized (function signature and property suggestions use the infromation from overloads' docs).
  • Also, when linking to a symbol representing an overloaded function with @link, the link displayed ends up leading to the first function declaration instead of its definition, which would be way more appropriate. For example, one might want to store the function in a new variable and use @see with @link over that variable's declaration to make it possible to find the function code and documentation by following the link. It does not make sense that the user ends up seeing one of the ovarloads just because it happens to be the first one.
  • I also occasionally see errors when linking to type properties / methods. I don't dare to say what is more sudden, how they appear or how they vanish. They are usually gone after typing something random and then pressing Ctrl+Z. I managed to capture one of them:
    image
    I also notice now there was an error in @implements, but it is gone now and I cannot reproduce it :(

Summary of feature requests

  • Always borrow description from function definition when displaying JSDoc for overload if no overload description is providd
  • Always display JSDoc information when hovering over function definition, including definitions of functions overloaded with @overload
  • Make @links lead to function definition instead of first declaration
  • Look for and fix errors in handling of @link / @implements / possibly other JSDoc tags used with imported types

Example code

Download code at ts-intellisense-jsdoc-overload.

function.ts

/**
 * @see {@link firstOrRest}
 * @param {T} value
 * @returns {[T]} value packed in array
 */
export function firstOrRest<T>(first: T): [T];
/**
 * @see {@link firstOrRest}
 * @param {*} first
 * @param {...T} rest
 * @returns {T[]} array of parameters after the first
 */
export function firstOrRest<T>(first: any, ...rest: T[]): T[];

/**
 * Returns array with first parameter if it is the only one provided,
 * or otherwise with all remaining parameters.
 * @param {*} first First parameter
 * @param {...*} rest Array of remaining parameters 
 * @returns {Array}
 */
export function firstOrRest(first: any, ...rest: any[]): any[] {
    return arguments.length > 1 ? rest : [first];
}

firstOrRest('first');
firstOrRest('first', 'second');

/**
 * @see {@link firstOrRest}
 */
const firstOrRestFunction = firstOrRest;

function.js

// @ts-check

/**
 * @see {@link firstOrRest}
 * @template T
 * @overload
 * @param {T} value
 * @returns {[T]} value packed in array
 */
/**
 * @see {@link firstOrRest}
 * @template T
 * @overload
 * @param {*} first
 * @param {...T} rest
 * @returns {T[]} array of parameters after the first
 */
/**
 * Returns array with first parameter if it is the only one provided,
 * or otherwise with all remaining parameters.
 * @param {*} first First parameter
 * @param {...*} rest Array of remaining parameters 
 * @returns {Array}
 */
export function firstOrRest(first, ...rest) {
    return arguments.length > 1 ? rest : [first];
}

firstOrRest('first');
firstOrRest('first', 'second');

/**
 * @see {@link firstOrRest}
 */
const firstOrRestFunction = firstOrRest;

index.d.ts

export interface Interface {
    /**
     * Returns array with first parameter if it is the only one provided,
     * or otherwise with all remaining parameters.
     * @param {*} first First parameter
     * @param {...*} rest Array of remaining parameters 
     * @returns {Array}
     */
    firstOrRest(first: any, ...rest: any[]): any[];
}

method.ts

import type { Interface } from '.';

export class Implementation implements Interface {
    /**
     * @see {@link Interface.firstOrRest}
     * @param {T} value
     * @returns {[T]} value packed in array
     */
    firstOrRest<T>(value: T): [T];
    /**
     * @see {@link Interface.firstOrRest}
     * @param {*} first
     * @param {...T} rest
     * @returns {T[]} array of parameters after the first
     */
    firstOrRest<T>(first: any, ...rest: T[]): T[];

    /**
     * @see {@link Interface.firstOrRest}
     */
    firstOrRest(first: any, ...rest: any[]): any[] {
        return arguments.length > 1 ? rest : [first];
    }
}

const { firstOrRest } = Implementation.prototype;

firstOrRest('first');
firstOrRest('first', 'second');

/**
 * @see {@link Implementation.firstOrRest}
 */
const firstOrRestFunction = firstOrRest;

method.js

// @ts-check

/**
 * @typedef {import ('.').Interface} Interface
 * @implements {Interface}
 */
export class Implementation {
    /**
     * @see {@link Interface.firstOrRest}
     * @template T
     * @overload
     * @param {T} value
     * @returns {[T]} value packed in array
     */
    /**
     * @see {@link Interface.firstOrRest}
     * @template T
     * @overload
     * @param {*} first
     * @param {...T} rest
     * @returns {T[]} array of parameters after the first
     */
    /**
     * @see {@link Interface.firstOrRest}
     * @param {*} first First parameter
     * @param {Array} rest Array of remaining parameters 
     * @returns {Array}
     */
    firstOrRest(first, ...rest) {
        return arguments.length > 1 ? rest : [first];
    }
}

const { firstOrRest } = Implementation.prototype;

firstOrRest('first');
firstOrRest('first', 'second');

/**
 * @see {@link Implementation.firstOrRest}
 */
const firstOrRestFunction = firstOrRest;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants