Open Evgenus opened 10 years ago
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?
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.
Fresh thought. Maybe support of JSDoc tags @augments
and @borrows
will helps.
See https://code.google.com/p/jsdoc-toolkit/wiki/TagReference
Some people have used @see
in the past e.g. :
@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.
@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.
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.
Surprisingly, I just run into this now. It's certainly surprising, I always assumed it worked automatically without having to duplicate comments. See https://github.com/types/npm-pug/pull/5#discussion_r78636341.
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.
Related issue: https://github.com/Microsoft/TypeScript/issues/3294
It would be great if this worked as @blakeembrey described 👌
Any progress?
Definitely would love to see this implemented somehow. A function with 3 overloaded type definitions needs copy/paste for all three... not fun...
@MichaelTontchev you mean that you can define overload now and it will work but with more copy-paste? can you show?
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.
@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.
Does anybody working on it?
I'm curious as well.
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).
Check this gist. It may give you an idea https://gist.github.com/seahindeniz/4de7ad774c1043ddb47b4080667bb06a
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.
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 */ }
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:
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 :(
any progress?😀
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):
And it shows correctly in the suggestion list, too:
The only downside is that you don't get parameter information at the call site:
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];
}
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.
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.
https://github.com/microsoft/TypeScript/issues/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.
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?