From a05699c9b985af708302b798324fdc0d592b1727 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 6 Jul 2023 13:23:06 -0700 Subject: [PATCH] Emit `@overload` comments on generated overloads in.d.ts (#54846) --- src/compiler/checker.ts | 4 + .../reference/jsFileFunctionOverloads.js | 29 +++++++ .../reference/jsFileFunctionOverloads2.js | 80 +++++++++++++++++++ .../reference/jsFileMethodOverloads.js | 20 +++++ .../reference/jsFileMethodOverloads2.js | 46 +++++++++++ tests/baselines/reference/overloadTag1.js | 52 ++++++++++++ tests/baselines/reference/overloadTag2.js | 17 ++++ .../reference/templateInsideCallback.js | 14 ++++ 8 files changed, 262 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0b67afefbb9..c03eb57618f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7440,6 +7440,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeArguments) { node.typeArguments = factory.createNodeArray(typeArguments); } + if (signature.declaration?.kind === SyntaxKind.JSDocSignature && signature.declaration.parent.kind === SyntaxKind.JSDocOverloadTag) { + const comment = getTextOfNode(signature.declaration.parent.parent, /*includeTrivia*/ true).slice(2, -2).split(/\r\n|\n|\r/).map(line => line.replace(/^\s+/, " ")).join("\n"); + addSyntheticLeadingComment(node, SyntaxKind.MultiLineCommentTrivia, comment, /*hasTrailingNewLine*/ true); + } cleanup?.(); return node; diff --git a/tests/baselines/reference/jsFileFunctionOverloads.js b/tests/baselines/reference/jsFileFunctionOverloads.js index 091b7c8a026..21f59c0e425 100644 --- a/tests/baselines/reference/jsFileFunctionOverloads.js +++ b/tests/baselines/reference/jsFileFunctionOverloads.js @@ -120,10 +120,39 @@ function flatMap(array, iterable) { //// [jsFileFunctionOverloads.d.ts] +/** + * @overload + * @param {number} x + * @returns {'number'} + */ declare function getTypeName(x: number): 'number'; +/** + * @overload + * @param {string} x + * @returns {'string'} + */ declare function getTypeName(x: string): 'string'; +/** + * @overload + * @param {boolean} x + * @returns {'boolean'} + */ declare function getTypeName(x: boolean): 'boolean'; +/** + * @template T + * @template U + * @overload + * @param {T[]} array + * @param {(x: T) => U[]} iterable + * @returns {U[]} + */ declare function flatMap(array: T[], iterable: (x: T) => U[]): U[]; +/** + * @template T + * @overload + * @param {T[][]} array + * @returns {T[]} + */ declare function flatMap(array: T[][]): T[]; /** * @template T diff --git a/tests/baselines/reference/jsFileFunctionOverloads2.js b/tests/baselines/reference/jsFileFunctionOverloads2.js index a84155ecc6a..1edaa734201 100644 --- a/tests/baselines/reference/jsFileFunctionOverloads2.js +++ b/tests/baselines/reference/jsFileFunctionOverloads2.js @@ -110,10 +110,90 @@ function flatMap(array, iterable) { //// [jsFileFunctionOverloads2.d.ts] +/** + * @overload + * @param {number} x + * @returns {'number'} + * + * @overload + * @param {string} x + * @returns {'string'} + * + * @overload + * @param {boolean} x + * @returns {'boolean'} + * + * @param {unknown} x + * @returns {string} + */ declare function getTypeName(x: number): 'number'; +/** + * @overload + * @param {number} x + * @returns {'number'} + * + * @overload + * @param {string} x + * @returns {'string'} + * + * @overload + * @param {boolean} x + * @returns {'boolean'} + * + * @param {unknown} x + * @returns {string} + */ declare function getTypeName(x: string): 'string'; +/** + * @overload + * @param {number} x + * @returns {'number'} + * + * @overload + * @param {string} x + * @returns {'string'} + * + * @overload + * @param {boolean} x + * @returns {'boolean'} + * + * @param {unknown} x + * @returns {string} + */ declare function getTypeName(x: boolean): 'boolean'; +/** + * @template T + * @template U + * @overload + * @param {T[]} array + * @param {(x: T) => U[]} iterable + * @returns {U[]} + * + * @overload + * @param {T[][]} array + * @returns {T[]} + * + * @param {unknown[]} array + * @param {(x: unknown) => unknown} iterable + * @returns {unknown[]} + */ declare function flatMap(array: T[], iterable: (x: T) => U[]): U[]; +/** + * @template T + * @template U + * @overload + * @param {T[]} array + * @param {(x: T) => U[]} iterable + * @returns {U[]} + * + * @overload + * @param {T[][]} array + * @returns {T[]} + * + * @param {unknown[]} array + * @param {(x: unknown) => unknown} iterable + * @returns {unknown[]} + */ declare function flatMap(array: T[][]): T[]; /** * @template T diff --git a/tests/baselines/reference/jsFileMethodOverloads.js b/tests/baselines/reference/jsFileMethodOverloads.js index a3b766cc6cf..f27531e3c88 100644 --- a/tests/baselines/reference/jsFileMethodOverloads.js +++ b/tests/baselines/reference/jsFileMethodOverloads.js @@ -107,8 +107,28 @@ declare class Example { */ constructor(value: T); value: T; + /** + * @overload + * @param {Example} this + * @returns {'number'} + */ getTypeName(this: Example): 'number'; + /** + * @overload + * @param {Example} this + * @returns {'string'} + */ getTypeName(this: Example): 'string'; + /** + * @template U + * @overload + * @param {(y: T) => U} fn + * @returns {U} + */ transform(fn: (y: T) => U): U; + /** + * @overload + * @returns {T} + */ transform(): T; } diff --git a/tests/baselines/reference/jsFileMethodOverloads2.js b/tests/baselines/reference/jsFileMethodOverloads2.js index 6ec653093f0..ee08aa6560f 100644 --- a/tests/baselines/reference/jsFileMethodOverloads2.js +++ b/tests/baselines/reference/jsFileMethodOverloads2.js @@ -101,8 +101,54 @@ declare class Example { */ constructor(value: T); value: T; + /** + * @overload + * @param {Example} this + * @returns {'number'} + * + * @overload + * @param {Example} this + * @returns {'string'} + * + * @returns {string} + */ getTypeName(this: Example): 'number'; + /** + * @overload + * @param {Example} this + * @returns {'number'} + * + * @overload + * @param {Example} this + * @returns {'string'} + * + * @returns {string} + */ getTypeName(this: Example): 'string'; + /** + * @template U + * @overload + * @param {(y: T) => U} fn + * @returns {U} + * + * @overload + * @returns {T} + * + * @param {(y: T) => unknown} [fn] + * @returns {unknown} + */ transform(fn: (y: T) => U): U; + /** + * @template U + * @overload + * @param {(y: T) => U} fn + * @returns {U} + * + * @overload + * @returns {T} + * + * @param {(y: T) => unknown} [fn] + * @returns {unknown} + */ transform(): T; } diff --git a/tests/baselines/reference/overloadTag1.js b/tests/baselines/reference/overloadTag1.js index 91efb30d7c5..feccb504f84 100644 --- a/tests/baselines/reference/overloadTag1.js +++ b/tests/baselines/reference/overloadTag1.js @@ -98,7 +98,59 @@ uncheckedInternally("zero", "one"); //// [overloadTag1.d.ts] +/** + * @overload + * @param {number} a + * @param {number} b + * @returns {number} + * + * @overload + * @param {string} a + * @param {boolean} b + * @returns {string} + * + * @param {string | number} a + * @param {string | number} b + * @returns {string | number} + */ export function overloaded(a: number, b: number): number; +/** + * @overload + * @param {number} a + * @param {number} b + * @returns {number} + * + * @overload + * @param {string} a + * @param {boolean} b + * @returns {string} + * + * @param {string | number} a + * @param {string | number} b + * @returns {string | number} + */ export function overloaded(a: string, b: boolean): string; +/** + * @overload + * @param {number} a + * @param {number} b + * @returns {number} + * + * @overload + * @param {string} a + * @param {boolean} b + * @returns {string} + */ export function uncheckedInternally(a: number, b: number): number; +/** + * @overload + * @param {number} a + * @param {number} b + * @returns {number} + * + * @overload + * @param {string} a + * @param {boolean} b + * @returns {string} + */ export function uncheckedInternally(a: string, b: boolean): string; diff --git a/tests/baselines/reference/overloadTag2.js b/tests/baselines/reference/overloadTag2.js index f2fa7d2a7b4..118f7d062be 100644 --- a/tests/baselines/reference/overloadTag2.js +++ b/tests/baselines/reference/overloadTag2.js @@ -73,8 +73,25 @@ var d = new Foo('str', 2); //// [overloadTag2.d.ts] export class Foo { + /** + * Should not have an implicit any error, because constructor's return type is always implicit + * @constructor + * @overload + * @param {string} a + * @param {number} b + */ constructor(a: string, b: number); + /** + * @constructor + * @overload + * @param {number} a + */ constructor(a: number); + /** + * @constructor + * @overload + * @param {string} a + */ constructor(a: string); #private; } diff --git a/tests/baselines/reference/templateInsideCallback.js b/tests/baselines/reference/templateInsideCallback.js index 9eeb034f8bc..21e5ecfdaab 100644 --- a/tests/baselines/reference/templateInsideCallback.js +++ b/tests/baselines/reference/templateInsideCallback.js @@ -114,7 +114,21 @@ function flatMap(array, iterable) { //// [templateInsideCallback.d.ts] +/** + * @overload + * @template T + * @template U + * @param {T[]} array + * @param {(x: T) => U[]} iterable + * @returns {U[]} + */ declare function flatMap(): any; +/** + * @overload + * @template T + * @param {T[][]} array + * @returns {T[]} + */ declare function flatMap(): any; /** * @typedef Oops