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

Js doc overloads #50789

Closed
wants to merge 4 commits into from
Closed

Js doc overloads #50789

wants to merge 4 commits into from

Conversation

apendua
Copy link
Contributor

@apendua apendua commented Sep 15, 2022

Fixes #25590

Since there was no final consensus, I ended up using a new @overload tag to ensure backwards compatibility, e.g.

/**
 * @overload
 * @param {number} x
 * @returns {'number'}
 */
/**
 * @overload
 * @param {string} x
 * @returns {'string'}
 */
/**
 * @overload
 * @param {boolean} x
 * @returns {'boolean'}
 */
/**
 * @param {unknown} x
 * @returns {string}
 */
function typeName(x) {
  return typeof x;
}

I would be happy to modify the implementation if someone suggests a better approach.

@typescript-bot typescript-bot added the For Backlog Bug PRs that fix a backlog bug label Sep 15, 2022
@ghost
Copy link

ghost commented Sep 15, 2022

CLA assistant check
All CLA requirements met.

@ValeTheVioletMote
Copy link

Looking forward to this!

@@ -3660,13 +3661,13 @@ namespace ts {

function hasTrailingCommentsAtPosition(pos: number) {
let result = false;
forEachTrailingCommentRange(currentSourceFile?.text || "", pos + 1, () => result = true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are these additional ends needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sandersn I did this because I wanted to avoid JSDoc nodes duplication in .d.ts file, e.g.

// file.js
/**
 * @overload
 * @param {string} value
 * @return {string}
 */
/**
 * @overload
 * @param {number} value
 * @return {number}
 */
/**
 * @overload
 * @param {unknown} value
 */
function myFunction(value) {}

would result in:

// file.d.ts
/**
 * @overload
 * @param {string} value
 */
declare function myFunction(value: string): string;
/**
 * @overload
 * @param {number} value
 */
declare function myFunction(value: number): number;
/**
 * @overload
 * @param {string} value
 */
/**
 * @overload
 * @param {number} value
 */
/**
 * @overload
 * @param {unknown} value
 */
declare function myFunction(value);

Being able to specify end allowed me to limit the JSDocs that are emitted for a given parent node.

However this seems to only be one of many weird consequences of synthesizing declarations, which as you suggested does not seem to be the proper approach anyway.

@@ -747,7 +748,7 @@ namespace ts {
* @returns If "reduce" is true, the accumulated value. If "reduce" is false, the first truthy
* return value of the callback.
*/
function iterateCommentRanges<T, U>(reduce: boolean, text: string, pos: number, trailing: boolean, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U | undefined) => U, state: T, initial?: U): U | undefined {
function iterateCommentRanges<T, U>(reduce: boolean, text: string, pos: number, end: number | undefined, trailing: boolean, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U | undefined) => U, state: T, initial?: U): U | undefined {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • same question about end in the file
  • extra space typo:
Suggested change
function iterateCommentRanges<T, U>(reduce: boolean, text: string, pos: number, end: number | undefined, trailing: boolean, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U | undefined) => U, state: T, initial?: U): U | undefined {
function iterateCommentRanges<T, U>(reduce: boolean, text: string, pos: number, end: number | undefined, trailing: boolean, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U | undefined) => U, state: T, initial?: U): U | undefined {

@@ -2677,12 +2677,11 @@ namespace ts {
}

export function copyLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) {
forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment));
forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, /*end*/ undefined, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question about end here

@@ -14,7 +14,7 @@ and limitations under the License.
***************************************************************************** */

declare namespace ts {
const versionMajorMinor = "4.9";
const versionMajorMinor = "4.8";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to merge from main at some point

@@ -0,0 +1,50 @@
// @allowJs: true
// @noEmit: true
// @filename: 0.js
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// @filename: 0.js
// @filename: jsFileMethodsOverloads.js

@@ -0,0 +1,61 @@
// @allowJs: true
// @noEmit: true
// @filename: 0.js
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// @filename: 0.js
// @filename: jsFileFunctionOverloads.js

@@ -0,0 +1,50 @@
// @allowJs: true
// @noEmit: true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use // @outDir: dist/ and // @declaration: true to make sure that js->d.ts conversion works too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sandersn I tried this but didn't see any changes in the baseline files. What outcome I should be observing?

Copy link
Member

@sandersn sandersn Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you remove @noEmit: true? You should see a baseline named jsFileMethodsOverloads.js and its last section should be a .d.ts file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sandersn Yup, that was it. Seems like it's working fine now. Thank you!

const newParameters: ParameterDeclaration[] = [];
for (const tag of jsDoc.tags) {
if (isJSDocParameterTag(tag) && tag.name.kind === SyntaxKind.Identifier) {
const newParameter = factory.createParameterDeclaration(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Synthesising declarations is not a technique that works in the typescript compiler. A better approach would be to make sure all the jsdoc nodes are still available to the checker. In the checker, make sure that each @overload results in a signature. You'll want to start near getSignatureFromDeclaration, or its callers, I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sandersn Agreed. I've also observed other BUGs related to IDE integrations that are coming from the fact that I am trying to synthesize those declarations, e.g. "did not expect identifier in trivia".

You'll want to start near getSignatureFromDeclaration, or its callers, I think.

Thank you for this suggestion! I've already tried that and it seems to be working much better:

https://github.com/microsoft/TypeScript/compare/main...apendua:js-doc-overload-tag?expand=1

How we should go about that? Should I close this pull request and open a new one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is up to you. I am fine with proceeding with this one; I squash merge PRs since it makes the git history easier to search.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sandersn I ended up opening a new PR here: #51234

I also used this opportunity to rebase onto the latest main. Thank you again for all your suggestions!

@sandersn sandersn self-assigned this Oct 17, 2022
@sandersn sandersn requested a review from navya9singh October 17, 2022 22:39
@apendua apendua mentioned this pull request Oct 19, 2022
@apendua
Copy link
Contributor Author

apendua commented Oct 19, 2022

Closing this PR in favor of: #51234

@apendua apendua closed this Oct 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

In JS, jsdoc should be able to declare functions as overloaded
4 participants