Skip to content

JSDoc for methods with multiple signatures #407

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
Evgenus opened this issue Aug 8, 2014 · 25 comments
Open

JSDoc for methods with multiple signatures #407

Evgenus opened this issue Aug 8, 2014 · 25 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Domain: JSDoc Relates to JSDoc parsing and type generation Suggestion An idea for TypeScript

Comments

@Evgenus
Copy link

Evgenus commented Aug 8, 2014

First I've thought about union types but they can solve only part of the problem. Original discussion started here. In case codeplex had been abandoned, I copy my question here.

Please take a look at this function. https://github.com/digitalbazaar/forge/blob/master/js/rsa.js#L802-L885 As you can see from comments there are a lot of ways to use it. If I need to make a type definitions for it (actually I do) with JSDoc Intellisense support, then I have to copy general function description like 10 times. This will make my definition 3 times longer than source function and also very hard to modify. In libraries like forge almost all functions have being made that way.

Can you give me some tip about making definitions in such circumstances?

@danquirk
Copy link
Member

danquirk commented Aug 8, 2014

What alternative would you like to see? You want to have the general description inherited when it's written on any overload? Or only when it's written against the implementation signature? Are argument descriptions inherited?

@Evgenus
Copy link
Author

Evgenus commented Aug 8, 2014

You want to have the general description inherited when it's written on any overload?

Yes. It would be nice.

Or only when it's written against the implementation signature?

I'm troubled about that only when writing definitions. So maybe for implementation it could be left as it is. My opinion is Yes.

Are argument descriptions inherited?

Yes, since there are already union types in jsdoc. Also jsdoc have names for arguments, not only index. I think in the most situations meaning of argument depends on its name and not on type. So if it is possible to show description for argument accordingly to its name, then argument description can be inherited.

@Evgenus
Copy link
Author

Evgenus commented Aug 10, 2014

Fresh thought. Maybe support of JSDoc tags @augments and @borrows will helps.

See https://code.google.com/p/jsdoc-toolkit/wiki/TagReference

@basarat
Copy link
Contributor

basarat commented Aug 11, 2014

@Evgenus
Copy link
Author

Evgenus commented Aug 11, 2014

@basarat @see doesn't help in VS right now. It shows only text of reference. And I can't imagine how to reference function/method with same name.

@basarat
Copy link
Contributor

basarat commented Aug 11, 2014

@see doesn't help in VS right now.

Agreed. Was just mentioning what people had tried. I'd like a @augments and @borrows jsdoc lookup in the language service as well.

@sebastian-lenz
Copy link

I've stumbled upon this problem too, copying the same comment to several signatures is not dry and leads to a lot of work and potential left overs when someone forgets to update all comments after some changes.

Some kind of inheritance makes sense to me. I would think of the implementation of a function to be the "root" containing the original comment. All signatures borrow this comment automatically unless it is (partly) overwritten in their own comments.

@blakeembrey
Copy link
Contributor

Surprisingly, I just run into this now. It's certainly surprising, I always assumed it worked automatically without having to duplicate comments. See typed-typings/npm-pug#5 (comment).

I would expect this to be a cascade. The first JSDoc description and params should be copied to the following overloads automatically, except you could override the description/param later on by writing it out explicitly. Is this is a reasonable change? If so, I'd be very interested in a trying to patch it if there's a pointer on where to get started. If only so I can avoid merging hard to maintain workarounds like duplicating documentation.

@mickdekkers
Copy link

Related issue: #3294

It would be great if this worked as @blakeembrey described 👌

@goodmind
Copy link

Any progress?

@RyanCavanaugh RyanCavanaugh added Needs Investigation This issue needs a team member to investigate its status. and removed Needs More Info The issue still hasn't been fully clarified Suggestion An idea for TypeScript labels Mar 26, 2018
@mhegazy mhegazy added Domain: JSDoc Relates to JSDoc parsing and type generation Suggestion An idea for TypeScript Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature and removed Needs Investigation This issue needs a team member to investigate its status. labels Mar 27, 2018
@MichaelTontchev
Copy link

Definitely would love to see this implemented somehow. A function with 3 overloaded type definitions needs copy/paste for all three... not fun...

@goodmind
Copy link

goodmind commented Apr 7, 2018

@MichaelTontchev you mean that you can define overload now and it will work but with more copy-paste? can you show?

@joma74
Copy link

joma74 commented Sep 2, 2018

Case here is a es5 class with a method member that is a candidate for method overloading. Using union types this member can be described as

/**
 * @todo See https://github.com/Microsoft/TypeScript/issues/407
 * 
 * @param {string} name 
 * @param {Function | BUFFERTYPE } [content]
 * @param {string} [type]
 * @return {Function | void}
 */
Runtime.prototype.createAttachment = function(name, content, type) {
...

In case of a Function for content, it should return a Function. In case of a BUFFERTYPE for content, it should return void.

Suggestion 1
Make overloaded definition in external d.ts(not on runtime.d.ts).
P.S. Tried to apply it on the js es5 class level or member method level, but found not way to accomplish that.

Suggestion 2
Make overload list definition in three comment blocks.

/**
 * @param {string} name 
 * @param {Function} [content]
 * @param {string} [type]
 * @return {Function}
 */
/**
 * @param {string} name 
 * @param {BUFFERTYPE} [content]
 * @param {string} [type]
 * @return {void}
 */
Runtime.prototype.createAttachment = function(name, content, type) {
...

P.S. Tried to apply it on the member method level, but only the first was considered by TS as method signature.

@Igmat
Copy link

Igmat commented Oct 2, 2018

@mhegazy what kind of feedback is missing?

IMO, everything is pretty straightforward:

export function A(a: string): string;
export function A(a: number): string;
/**
 * Overloaded comment only for this signature
 * @description overloaded description only for this signature
 */
export function A(a: string, b: string): string;
/**
 * @param b overloaded description for `b` argument only for this signature
 * @returns overloaded description for `return` only for this signature
 */
export function A(a: string, b: number): string;
export function A(a: number, b: string): string;
export function A(a: number, b: number): string;
/**
 * Default comment for function A
 * @description default description for A
 * @param a default description for `a` argument
 * @param [b] default description for `b` argument 
 * @returns default comment for `return`
 */
export function A(a: string | number, b?: string | number): string {
    // implementation
}

So, each time when JSDoc is shown, it should merge default docs (that came from implementation in case of .ts file, or from most generic overload in case of .d.ts file) with docs that belong to particular overload, where last one takes precedence.

@captain-yossarian
Copy link

Does anybody working on it?

@greaterking
Copy link

I'm curious as well.

@webOS101
Copy link

Ran into this one, too. Cascading down the first description would be the best, I think. Would greatly reduce the size of .d.ts files that document overloaded functions (In my case, curried functions).

@seahindeniz
Copy link

Check this gist. It may give you an idea https://gist.github.com/seahindeniz/4de7ad774c1043ddb47b4080667bb06a

@sandersn
Copy link
Member

Complicating things even further, the new @deprecated tag would be ambiguous if appearing on the first signature; overloads are sometimes deprecated individually, but it's also common to deprecate an entire function.

As of the 4.0 beta, quick info says a function is deprecated if -- and only if -- the first signature has @deprecated. But the checker says a function is deprecated if any signature is deprecated. This is likely to change, but it illustrates how hard it is to find the correct behaviour.

@chharvey
Copy link

chharvey commented Mar 29, 2021

For what it’s worth, JSDoc has an @inheritdoc tag; maybe it can be repurposed for TypeScript documentation?

I like the idea of cascading. If an overload has @inheritdoc, it would inherit everything from the overload above, but would also include any additional documentation. This would help in the case of the new @deprecated tag.

Example 1: basic @inheritdoc usage

interface Vector {
   /**
    * Add a vector to this vector.
    * @param v - a vector to be added
    * @return - the vector sum
    */
   plus(v: Vector): Vector;
   /**
    * @inheritdoc
    * @param v - a tuple of 3 numbers to be added
    */
   // should inherit the description and @return tag, but not the @param tag
   plus(v: [number, number, number]): Vector;
}

Example 2: marking only last overload(s) as @deprecated

/** A function that does something. */
function foo(x: unknown): void;
/** @inheritdoc */
function foo(x: unknown, y: unknown): void;
/** @inheritdoc @deprecated */
function foo(x: unknown, y: unknown, z: unknown): void;
function foo(...args: any[]): any { /* implementation */ }

(This requires moving any deprecated overloads to the bottom, as we don’t want non-deprecated overloads to inherit the tag.)

/** A function that does something. */
function foo(x: unknown): void;
-/** @inheritdoc */
-function foo(x: unknown, y: unknown): void;
/** @inheritdoc */
function foo(x: unknown, y: unknown, z: unknown): void;
+/** @inheritdoc @deprecated */
+function foo(x: unknown, y: unknown): void;
# need to move 2-arg overload to bottom, otherwise the 3-arg overload would inherit the `@deprecated` tag
function foo(...args: any[]): any { /* implementation */ }

@KutnerUri
Copy link

KutnerUri commented Jul 13, 2021

I found you can just put the main declaration first, and the overloads after, like so:

/** deserialize a componnet id from raw object */
static fromObject(object: ComponentIdObj, scope?: string) {
	// ...
}
/** provide scope separaetly, e.g. fromObject({ name: 'button' }, 'teambit.base-ui') */
static fromObject(object: Omit<ComponentIdObj, 'scope'>, scope: string): ComponentID;
static fromObject(object: ComponentIdObj, scope?: string): ComponentID;

VSC will know to show the correct overload description:

Screen Shot 2021-07-13 at 12 00 17

Screen Shot 2021-07-13 at 12 00 32

VSC isn't showing the strikethrough for @deprecated overloads, though.

EDIT:
I'm getting Function implementation name must be 'fromObject'.ts(2389) on the next method, so maybe it's not working correctly with typescript :(

@unbyte
Copy link

unbyte commented Nov 10, 2021

any progress?😀

@P-Daddy
Copy link

P-Daddy commented Mar 24, 2022

There is sort of a way to do this.

You can create an interface with a single any member having the same name as your overloaded function and apply docs to that. The downside is that @parameter docs don't seem to propagate correctly, at least not in VS Code.

interface Docs {
    /**
     * Documentation for `foo` function.
     * @param param1 Param 1 is important.
     * @param param2 So is param 2!
     * @returns A tuple of its arguments.
     * 
     * @example
     * ```ts
     * const result = foo("hello", "goodbye");
     * ```
     */
    foo: any;
}

interface Overloads extends Docs {
    foo<T>(param1: T, param2: T): T[];
    foo<T, U>(param1: T, param2: U): [T, U];
}

Hovering over either overload shows the correct documentation (but keep reading after the pictures for a caveat):

image

And it shows correctly in the suggestion list, too:

image

The only downside is that you don't get parameter information at the call site:

image

So you still have to duplicate the parameter documentation for each overload if you want that.

interface Overloads extends Docs {
    /**
     * @param param1 Param 1 is important.
     * @param param2 So is param 2!
     */
    foo<T>(param1: T, param2: T): T[];
    /**
     * @param param1 Param 1 is important.
     * @param param2 So is param 2!
     */
    foo<T, U>(param1: T, param2: U): [T, U];
}

image

Although notice that you lose the @returns and @example in this case.

Personally, if the parameter information would propagate correctly, and if adding documentation didn't lose some that was there before, I'd consider this issue resolved. But I'm not actually sure if it's a TypeScript issue or a VS Code issue.

@geoffreytools
Copy link

Something I noticed with higher order functions: since there is no way to have a JSDoc description show up in a tooltip when hovering over the return value of a function, using a workaround such as the one @P-Daddy suggested is going to totally obfuscate the little information the user had left: const foo: Overloads is not a tooltip I am happy to see, so I choose to bear with the duplication because a function signature is already something.

Now I would love it if there was a way to control how type aliases and interfaces show up in tooltips, but having some way to manage JSDoc duplication would also help.

layershifter added a commit to microsoft/griffel that referenced this issue Nov 12, 2024
* Deprecated tag is needed for all overloads of deprecated shorthand functions to properly communicate that shorthand is deprecated

Refer: microsoft/TypeScript#407

* Change files

* Update change/@griffel-core-e0dc7909-f321-4c3e-b9f8-0a2a280e37cf.json

---------

Co-authored-by: Oleksandr Fediashov <[email protected]>
@SamB
Copy link

SamB commented Nov 19, 2024

#51005 has a much clearer title: this title made me think it was a stale dupe of the issue for implementing @overload for use with JSDoc to declare types in JavaScript files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Domain: JSDoc Relates to JSDoc parsing and type generation Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests