From ec9203f3a02cb7f8b81ae366ef79cfd7db67434b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 26 May 2026 13:18:41 -0700 Subject: [PATCH 1/7] Revise logic for gathering JSDoc @template type parameters --- internal/parser/reparser.go | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/internal/parser/reparser.go b/internal/parser/reparser.go index 8a2aa2f158a..c99c83d406f 100644 --- a/internal/parser/reparser.go +++ b/internal/parser/reparser.go @@ -52,7 +52,7 @@ func (p *Parser) reparseUnhosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Nod break } typeAlias := p.factory.NewJSTypeAliasDeclaration(nil, p.addDeepCloneReparse(tag.AsJSDocTypedefTag().Name()), nil, nil) - typeAlias.AsTypeAliasDeclaration().TypeParameters = p.gatherTypeParameters(jsDoc, tag) + typeAlias.AsTypeAliasDeclaration().TypeParameters = p.gatherTypeParameters(jsDoc, true /*typedefOrCallback*/) var t *ast.Node switch typeExpression.Kind { case ast.KindJSDocTypeExpression: @@ -74,7 +74,7 @@ func (p *Parser) reparseUnhosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Nod } functionType := p.reparseJSDocSignature(callbackTag.TypeExpression, tag, jsDoc, tag, nil) typeAlias := p.factory.NewJSTypeAliasDeclaration(nil, p.addDeepCloneReparse(callbackTag.FullName), nil, functionType) - typeAlias.AsTypeAliasDeclaration().TypeParameters = p.gatherTypeParameters(jsDoc, tag) + typeAlias.AsTypeAliasDeclaration().TypeParameters = p.gatherTypeParameters(jsDoc, true /*typedefOrCallback*/) p.finishReparsedNode(typeAlias, tag) p.jsdocInfos = append(p.jsdocInfos, JSDocInfo{parent: typeAlias, jsDocs: []*ast.Node{jsDoc}}) typeAlias.Flags |= ast.NodeFlagsHasJSDoc @@ -119,7 +119,7 @@ func (p *Parser) reparseJSDocSignature(jsSignature *ast.Node, fun *ast.Node, jsD } if tag.Kind != ast.KindJSDocCallbackTag { - signature.FunctionLikeData().TypeParameters = p.gatherTypeParameters(jsDoc, tag) + signature.FunctionLikeData().TypeParameters = p.gatherTypeParameters(jsDoc, false /*typedefOrCallback*/) } parameters := p.nodeSliceArena.NewSlice(0) for _, param := range jsSignature.Parameters() { @@ -223,26 +223,16 @@ func (p *Parser) reparseJSDocComment(node *ast.Node, tag *ast.Node) { } } -func (p *Parser) gatherTypeParameters(j *ast.Node, tagWithTypeParameters *ast.Node) *ast.NodeList { +func (p *Parser) gatherTypeParameters(j *ast.Node, typedefOrCallback bool) *ast.NodeList { var typeParameters []*ast.Node pos := -1 endPos := -1 firstTemplate := true - // type parameters only apply to the tag or node they occur before, so record a place to stop - start := 0 - for i, other := range j.AsJSDoc().Tags.Nodes { - if other == tagWithTypeParameters { - break - } - if other.Kind == ast.KindJSDocTypedefTag || other.Kind == ast.KindJSDocCallbackTag || other.Kind == ast.KindJSDocOverloadTag { - start = i + 1 - } - } - for i, tag := range j.AsJSDoc().Tags.Nodes { - if tag == tagWithTypeParameters { - break + for _, tag := range j.AsJSDoc().Tags.Nodes { + if !typedefOrCallback && (ast.IsJSDocTypedefTag(tag) || ast.IsJSDocCallbackTag(tag)) { + return nil } - if i < start || tag.Kind != ast.KindJSDocTemplateTag { + if !ast.IsJSDocTemplateTag(tag) { continue } if firstTemplate { @@ -250,7 +240,6 @@ func (p *Parser) gatherTypeParameters(j *ast.Node, tagWithTypeParameters *ast.No firstTemplate = false } endPos = tag.End() - constraint := tag.AsJSDocTemplateTag().Constraint firstTypeParameter := true for _, tp := range tag.TypeParameters() { @@ -389,19 +378,19 @@ func (p *Parser) reparseHosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Node) case ast.KindJSDocTemplateTag: if fun := getFunctionLikeHost(parent); fun != nil { if fun.TypeParameters() == nil && fun.FunctionLikeData().FullSignature == nil { - fun.FunctionLikeData().TypeParameters = p.gatherTypeParameters(jsDoc, nil /*tagWithTypeParameters*/) + fun.FunctionLikeData().TypeParameters = p.gatherTypeParameters(jsDoc, false /*typedefOrCallback*/) p.finishMutatedNode(fun) } } else if parent.Kind == ast.KindClassDeclaration { class := parent.AsClassDeclaration() if class.TypeParameters == nil { - class.TypeParameters = p.gatherTypeParameters(jsDoc, nil /*tagWithTypeParameters*/) + class.TypeParameters = p.gatherTypeParameters(jsDoc, false /*typedefOrCallback*/) p.finishMutatedNode(parent) } } else if parent.Kind == ast.KindClassExpression { class := parent.AsClassExpression() if class.TypeParameters == nil { - class.TypeParameters = p.gatherTypeParameters(jsDoc, nil /*tagWithTypeParameters*/) + class.TypeParameters = p.gatherTypeParameters(jsDoc, false /*typedefOrCallback*/) p.finishMutatedNode(parent) } } From 44a3f08538dead4311855e2c64dda49d14891b55 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 26 May 2026 13:20:01 -0700 Subject: [PATCH 2/7] Error on @template inside @overload and @typedef sections --- internal/parser/jsdoc.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/parser/jsdoc.go b/internal/parser/jsdoc.go index 51654d2576f..372fb5d16d7 100644 --- a/internal/parser/jsdoc.go +++ b/internal/parser/jsdoc.go @@ -865,9 +865,10 @@ func (p *Parser) parseNestedTypeLiteral(typeExpression *ast.Node, name *ast.Enti p.rewind(state) break } - if child.Kind == ast.KindJSDocParameterTag || child.Kind == ast.KindJSDocPropertyTag { + switch child.Kind { + case ast.KindJSDocParameterTag, ast.KindJSDocPropertyTag: children = append(children, child) - } else if child.Kind == ast.KindJSDocTemplateTag { + case ast.KindJSDocTemplateTag: p.parseErrorAtRange(child.TagName().Loc, diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag) } } @@ -1007,11 +1008,11 @@ func (p *Parser) parseTypedefTag(start int, tagName *ast.IdentifierNode, indent p.rewind(state) break } - if child.Kind == ast.KindJSDocTemplateTag { - break - } hasChildren = true - if child.Kind == ast.KindJSDocTypeTag { + switch child.Kind { + case ast.KindJSDocTemplateTag: + p.parseErrorAtRange(child.TagName().Loc, diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag) + case ast.KindJSDocTypeTag: if childTypeTag == nil { childTypeTag = child.AsJSDocTypeTag() } else { @@ -1020,9 +1021,8 @@ func (p *Parser) parseTypedefTag(start int, tagName *ast.IdentifierNode, indent related := ast.NewDiagnostic(nil, core.NewTextRange(0, 0), diagnostics.The_tag_was_first_specified_here) lastError.AddRelatedInfo(related) } - break } - } else { + default: jsdocPropertyTags = append(jsdocPropertyTags, child) } } @@ -1082,9 +1082,9 @@ func (p *Parser) parseCallbackTagParameters(indent int) *ast.NodeList { } if child.Kind == ast.KindJSDocTemplateTag { p.parseErrorAtRange(child.TagName().Loc, diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag) - break + } else { + parameters = append(parameters, child) } - parameters = append(parameters, child) } return p.newNodeList(core.NewTextRange(pos, p.nodePos()), parameters) } From fe50f27867523fb9bd9e65c4424f10066cd930cf Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 27 May 2026 15:34:21 -0700 Subject: [PATCH 3/7] Document in CHANGES.md --- CHANGES.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index b5e737e7f07..28feb1a8c7d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -274,6 +274,42 @@ function f(cu) { In Strada, `cu` incorrectly narrows to `C` inside the `if` block, unlike with TS assertion syntax. In Corsa, the behaviour is the same between TS and JS. +#### `@overload` with arrow functions and function expressions + +In Strada, `@overload` can be used in JSDoc annotations for arrow functions and function expressions. Corsa more closely aligns with TypeScript by internally translating JSDoc constructs into synthetic TypeScript constructs which are then checked. However, since TypeScript itself currently doesn't support overload declarations with arrow function and function expressions, Corsa ignores `@overload` annotations on those constructs. Instead of writing: + +```js +/** + * @overload + * @param {string} x + * @returns {string} + * + * @overload + * @param {number} x + * @returns {number} + * + * @param {string | number} x + * @returns {string | number} + */ +let f = x => x; +``` + +You should write: + +```js +/** + * @type {{ + * (x: string): string; + * (x: number): number; + * }} + * @param {string | number} x + * @returns {any} + */ +const f = x => x; +``` + +This works with both TS6 and TS7. Note the change to `any` for the return type annotation. This is to satisfy the assignment check. + ### Expandos #### Constructor functions are no longer supported From 58551bf394b561e5fafc8d6dafe4854ba8d919f9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 27 May 2026 15:39:39 -0700 Subject: [PATCH 4/7] Accept new baselines --- .../conformance/jsdocVariadicInOverload.js | 2 +- .../conformance/jsdocVariadicInOverload.types | 6 +- ...nferenceFromAnnotatedFunctionJs.errors.txt | 42 ---------- ...OnlyInferenceFromAnnotatedFunctionJs.types | 6 +- .../compiler/jsFileFunctionOverloads2.js | 28 +------ .../compiler/jsFileFunctionOverloads2.types | 4 +- .../jsFileFunctionOverloads2.types.diff | 8 +- .../compiler/jsFileMethodOverloads2.js | 2 +- .../compiler/jsFileMethodOverloads2.types | 2 +- .../jsFileMethodOverloads2.types.diff | 2 +- .../templateInsideCallback.errors.txt | 48 ++++++++--- .../templateInsideCallback.errors.txt.diff | 84 ++++++++++--------- .../conformance/templateInsideCallback.js | 10 ++- .../conformance/templateInsideCallback.types | 2 +- .../templateInsideCallback.types.diff | 2 +- ...nceFromAnnotatedFunctionJs.errors.txt.diff | 46 ---------- ...nferenceFromAnnotatedFunctionJs.types.diff | 20 ----- .../compiler/jsFileFunctionOverloads2.js.diff | 28 +------ .../compiler/jsFileMethodOverloads2.js.diff | 9 +- .../templateInsideCallback.js.diff | 12 ++- 20 files changed, 117 insertions(+), 246 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt delete mode 100644 testdata/baselines/reference/submoduleAccepted/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt.diff delete mode 100644 testdata/baselines/reference/submoduleAccepted/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types.diff diff --git a/testdata/baselines/reference/conformance/jsdocVariadicInOverload.js b/testdata/baselines/reference/conformance/jsdocVariadicInOverload.js index 911568c56bd..b090972cbcc 100644 --- a/testdata/baselines/reference/conformance/jsdocVariadicInOverload.js +++ b/testdata/baselines/reference/conformance/jsdocVariadicInOverload.js @@ -127,7 +127,7 @@ export declare class Processor} * Current processor. */ - use(preset?: string | null | undefined): Processor; + use = [], Input extends Node | string | undefined = undefined, Output = Input>(preset?: string | null | undefined): Processor; /** * @overload * @param {string | null | undefined} [preset] diff --git a/testdata/baselines/reference/conformance/jsdocVariadicInOverload.types b/testdata/baselines/reference/conformance/jsdocVariadicInOverload.types index 5514b6480b1..58d25c0cc28 100644 --- a/testdata/baselines/reference/conformance/jsdocVariadicInOverload.types +++ b/testdata/baselines/reference/conformance/jsdocVariadicInOverload.types @@ -41,7 +41,7 @@ export class Processor { * Current processor. */ use(value, ...parameters) { ->use : { (preset?: string | null | undefined): Processor; = [], Input extends Node | string | undefined = undefined, Output = Input>(plugin: number, ...parameters: (Parameters | [boolean])): Processor; } +>use : { = [], Input_1 extends Node | string | undefined = undefined, Output_1 = Input_1>(preset?: string | null | undefined): Processor; = [], Input_1 extends Node | string | undefined = undefined, Output_1 = Input_1>(plugin: number, ...parameters: (Parameters_1 | [boolean])): Processor; } >value : string | number | boolean | null | undefined >parameters : unknown[] @@ -64,9 +64,9 @@ var x = 1, y = 2, z = 3; p.use(x, y, z); >p.use(x, y, z) : Processor ->p.use : { (preset?: string | null | undefined): Processor; = [], Input extends Node | string | undefined = undefined, Output = Input>(plugin: number, ...parameters: Parameters | [boolean]): Processor; } +>p.use : { = [], Input extends Node | string | undefined = undefined, Output = Input>(preset?: string | null | undefined): Processor; = [], Input extends Node | string | undefined = undefined, Output = Input>(plugin: number, ...parameters: Parameters | [boolean]): Processor; } >p : Processor ->use : { (preset?: string | null | undefined): Processor; = [], Input extends Node | string | undefined = undefined, Output = Input>(plugin: number, ...parameters: Parameters | [boolean]): Processor; } +>use : { = [], Input extends Node | string | undefined = undefined, Output = Input>(preset?: string | null | undefined): Processor; = [], Input extends Node | string | undefined = undefined, Output = Input>(plugin: number, ...parameters: Parameters | [boolean]): Processor; } >x : number >y : number >z : number diff --git a/testdata/baselines/reference/submodule/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt b/testdata/baselines/reference/submodule/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt deleted file mode 100644 index b812e341fba..00000000000 --- a/testdata/baselines/reference/submodule/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt +++ /dev/null @@ -1,42 +0,0 @@ -index.js(2,28): error TS2304: Cannot find name 'B'. -index.js(2,42): error TS2304: Cannot find name 'A'. -index.js(2,48): error TS2304: Cannot find name 'B'. -index.js(2,67): error TS2304: Cannot find name 'B'. -index.js(10,12): error TS2315: Type 'Funcs' is not generic. - - -==== index.js (5 errors) ==== - /** - * @typedef {{ [K in keyof B]: { fn: (a: A, b: B) => void; thing: B[K]; } }} Funcs - ~ -!!! error TS2304: Cannot find name 'B'. - ~ -!!! error TS2304: Cannot find name 'A'. - ~ -!!! error TS2304: Cannot find name 'B'. - ~ -!!! error TS2304: Cannot find name 'B'. - * @template A - * @template {Record} B - */ - - /** - * @template A - * @template {Record} B - * @param {Funcs} fns - ~~~~~~~~~~~ -!!! error TS2315: Type 'Funcs' is not generic. - * @returns {[A, B]} - */ - function foo(fns) { - return /** @type {any} */ (null); - } - - const result = foo({ - bar: { - fn: - /** @param {string} a */ - (a) => {}, - thing: "asd", - }, - }); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types b/testdata/baselines/reference/submodule/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types index e97a7de9d68..2f4658db577 100644 --- a/testdata/baselines/reference/submodule/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types +++ b/testdata/baselines/reference/submodule/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types @@ -15,15 +15,15 @@ */ function foo(fns) { >foo : >(fns: Funcs) => [A, B] ->fns : any +>fns : Funcs return /** @type {any} */ (null); >(null) : any } const result = foo({ ->result : [any, Record] ->foo({ bar: { fn: /** @param {string} a */ (a) => {}, thing: "asd", },}) : [any, Record] +>result : [string, { bar: string; }] +>foo({ bar: { fn: /** @param {string} a */ (a) => {}, thing: "asd", },}) : [string, { bar: string; }] >foo : >(fns: Funcs) => [A, B] >{ bar: { fn: /** @param {string} a */ (a) => {}, thing: "asd", },} : { bar: { fn: (a: string) => void; thing: string; }; } diff --git a/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.js b/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.js index 38621c00797..c713c24bd81 100644 --- a/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.js +++ b/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.js @@ -120,30 +120,4 @@ declare function getTypeName(x: boolean): 'boolean'; */ declare const identity: (x: T) => T; declare function flatMap(array: T[], iterable: (x: T) => U[]): U[]; -declare function flatMap(array: T[][]): T[]; - - -//// [DtsFileErrors] - - -dist/jsFileFunctionOverloads2.d.ts(11,33): error TS2304: Cannot find name 'T'. -dist/jsFileFunctionOverloads2.d.ts(11,41): error TS2304: Cannot find name 'T'. - - -==== dist/jsFileFunctionOverloads2.d.ts (2 errors) ==== - declare function getTypeName(x: number): 'number'; - declare function getTypeName(x: string): 'string'; - declare function getTypeName(x: boolean): 'boolean'; - /** - * @template T - * @param {T} x - * @returns {T} - */ - declare const identity: (x: T) => T; - declare function flatMap(array: T[], iterable: (x: T) => U[]): U[]; - declare function flatMap(array: T[][]): T[]; - ~ -!!! error TS2304: Cannot find name 'T'. - ~ -!!! error TS2304: Cannot find name 'T'. - \ No newline at end of file +declare function flatMap(array: T[][]): T[]; diff --git a/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.types b/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.types index ffb8eadd959..1d969591c8f 100644 --- a/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.types +++ b/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.types @@ -55,10 +55,10 @@ const identity = x => x; * @returns {unknown[]} */ function flatMap(array, iterable = identity) { ->flatMap : { (array: T[], iterable: (x: T) => U[]): U[]; (array: T[][]): T[]; } +>flatMap : { (array: T_1[], iterable: (x: T_1) => U_1[]): U_1[]; (array: T_1[][]): T_1[]; } >array : unknown[] >iterable : (x: unknown) => unknown ->identity : (x: T) => T +>identity : (x: T_1) => T_1 /** @type {unknown[]} */ const result = []; diff --git a/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.types.diff b/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.types.diff index 4d44db9d4bc..ff29f21a6e8 100644 --- a/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.types.diff +++ b/testdata/baselines/reference/submodule/compiler/jsFileFunctionOverloads2.types.diff @@ -14,11 +14,7 @@ */ function flatMap(array, iterable = identity) { ->flatMap : { (array: T[], iterable: (x: T) => U[]): U[]; (array: T[][]): T[]; } -+>flatMap : { (array: T[], iterable: (x: T) => U[]): U[]; (array: T[][]): T[]; } ++>flatMap : { (array: T_1[], iterable: (x: T_1) => U_1[]): U_1[]; (array: T_1[][]): T_1[]; } >array : unknown[] >iterable : (x: unknown) => unknown -->identity : (x: T_1) => T_1 -+>identity : (x: T) => T - - /** @type {unknown[]} */ - const result = []; \ No newline at end of file + >identity : (x: T_1) => T_1 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.js b/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.js index 2f5d96d4995..26f2ccb2013 100644 --- a/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.js +++ b/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.js @@ -150,5 +150,5 @@ declare class Example { * @param {(y: T) => unknown} [fn] * @returns {unknown} */ - transform(): T; + transform(): T; } diff --git a/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.types b/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.types index fcb6976b81b..8a317ac2b56 100644 --- a/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.types +++ b/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.types @@ -56,7 +56,7 @@ * @returns {unknown} */ transform(fn) { ->transform : { (fn: (y: T) => U): U; (): T; } +>transform : { (fn: (y: T) => U_1): U_1; (): T; } >fn : ((y: T) => unknown) | undefined return fn ? fn(this.value) : this.value; diff --git a/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.types.diff b/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.types.diff index 419e54ad7ce..adcbca5eb1d 100644 --- a/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.types.diff +++ b/testdata/baselines/reference/submodule/compiler/jsFileMethodOverloads2.types.diff @@ -14,7 +14,7 @@ */ transform(fn) { ->transform : { (fn: (y: T) => U): U; (): T; } -+>transform : { (fn: (y: T) => U): U; (): T; } ++>transform : { (fn: (y: T) => U_1): U_1; (): T; } >fn : ((y: T) => unknown) | undefined return fn ? fn(this.value) : this.value; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.errors.txt b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.errors.txt index b23dc638cf7..1e98a9626ab 100644 --- a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.errors.txt @@ -1,21 +1,36 @@ +templateInsideCallback.js(3,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag +templateInsideCallback.js(4,15): error TS2304: Cannot find name 'T'. +templateInsideCallback.js(5,15): error TS2304: Cannot find name 'T'. templateInsideCallback.js(9,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag +templateInsideCallback.js(10,12): error TS2304: Cannot find name 'T'. +templateInsideCallback.js(11,14): error TS2304: Cannot find name 'T'. templateInsideCallback.js(15,11): error TS2315: Type 'Call' is not generic. templateInsideCallback.js(15,16): error TS2304: Cannot find name 'T'. templateInsideCallback.js(17,18): error TS7006: Parameter 'x' implicitly has an 'any' type. templateInsideCallback.js(23,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag -templateInsideCallback.js(29,5): error TS2394: This overload signature is not compatible with its implementation signature. -templateInsideCallback.js(29,5): error TS7012: This overload implicitly returns the type 'any' because it lacks a return type annotation. templateInsideCallback.js(30,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag -templateInsideCallback.js(37,5): error TS7012: This overload implicitly returns the type 'any' because it lacks a return type annotation. +templateInsideCallback.js(31,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag +templateInsideCallback.js(32,12): error TS2304: Cannot find name 'T'. +templateInsideCallback.js(33,16): error TS2304: Cannot find name 'T'. +templateInsideCallback.js(33,22): error TS2304: Cannot find name 'U'. +templateInsideCallback.js(34,14): error TS2304: Cannot find name 'U'. templateInsideCallback.js(38,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag +templateInsideCallback.js(39,12): error TS2304: Cannot find name 'T'. +templateInsideCallback.js(40,14): error TS2304: Cannot find name 'T'. -==== templateInsideCallback.js (10 errors) ==== +==== templateInsideCallback.js (19 errors) ==== /** * @typedef Oops * @template T + ~~~~~~~~ +!!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag * @property {T} a + ~ +!!! error TS2304: Cannot find name 'T'. * @property {T} b + ~ +!!! error TS2304: Cannot find name 'T'. */ /** * @callback Call @@ -23,7 +38,11 @@ templateInsideCallback.js(38,5): error TS8039: A JSDoc '@template' tag may not f ~~~~~~~~ !!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag * @param {T} x + ~ +!!! error TS2304: Cannot find name 'T'. * @returns {T} + ~ +!!! error TS2304: Cannot find name 'T'. */ /** * @template T @@ -50,28 +69,35 @@ templateInsideCallback.js(38,5): error TS8039: A JSDoc '@template' tag may not f /** * @overload - ~~~~~~~~ -!!! error TS2394: This overload signature is not compatible with its implementation signature. -!!! related TS2750 templateInsideCallback.js:47:10: The implementation signature is declared here. - ~~~~~~~~ -!!! error TS7012: This overload implicitly returns the type 'any' because it lacks a return type annotation. * @template T ~~~~~~~~ !!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag * @template U + ~~~~~~~~ +!!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag * @param {T[]} array + ~ +!!! error TS2304: Cannot find name 'T'. * @param {(x: T) => U[]} iterable + ~ +!!! error TS2304: Cannot find name 'T'. + ~ +!!! error TS2304: Cannot find name 'U'. * @returns {U[]} + ~ +!!! error TS2304: Cannot find name 'U'. */ /** * @overload - ~~~~~~~~ -!!! error TS7012: This overload implicitly returns the type 'any' because it lacks a return type annotation. * @template T ~~~~~~~~ !!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag * @param {T[][]} array + ~ +!!! error TS2304: Cannot find name 'T'. * @returns {T[]} + ~ +!!! error TS2304: Cannot find name 'T'. */ /** * @param {unknown[]} array diff --git a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.errors.txt.diff b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.errors.txt.diff index 7e9dc1d6ce8..8eb435384b1 100644 --- a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.errors.txt.diff +++ b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.errors.txt.diff @@ -3,20 +3,24 @@ @@= skipped -0, +0 lines =@@ -error TS-1: Pre-emit (11) and post-emit (13) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here! -templateInsideCallback.js(2,13): error TS8021: JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags. ++templateInsideCallback.js(3,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag ++templateInsideCallback.js(4,15): error TS2304: Cannot find name 'T'. ++templateInsideCallback.js(5,15): error TS2304: Cannot find name 'T'. templateInsideCallback.js(9,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag --templateInsideCallback.js(10,12): error TS2304: Cannot find name 'T'. + templateInsideCallback.js(10,12): error TS2304: Cannot find name 'T'. ++templateInsideCallback.js(11,14): error TS2304: Cannot find name 'T'. templateInsideCallback.js(15,11): error TS2315: Type 'Call' is not generic. +templateInsideCallback.js(15,16): error TS2304: Cannot find name 'T'. templateInsideCallback.js(17,18): error TS7006: Parameter 'x' implicitly has an 'any' type. templateInsideCallback.js(23,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag -+templateInsideCallback.js(29,5): error TS2394: This overload signature is not compatible with its implementation signature. -+templateInsideCallback.js(29,5): error TS7012: This overload implicitly returns the type 'any' because it lacks a return type annotation. templateInsideCallback.js(30,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag --templateInsideCallback.js(32,12): error TS2304: Cannot find name 'T'. --templateInsideCallback.js(33,16): error TS2304: Cannot find name 'T'. -+templateInsideCallback.js(37,5): error TS7012: This overload implicitly returns the type 'any' because it lacks a return type annotation. ++templateInsideCallback.js(31,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag + templateInsideCallback.js(32,12): error TS2304: Cannot find name 'T'. + templateInsideCallback.js(33,16): error TS2304: Cannot find name 'T'. ++templateInsideCallback.js(33,22): error TS2304: Cannot find name 'U'. ++templateInsideCallback.js(34,14): error TS2304: Cannot find name 'U'. templateInsideCallback.js(38,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag --templateInsideCallback.js(39,12): error TS2304: Cannot find name 'T'. + templateInsideCallback.js(39,12): error TS2304: Cannot find name 'T'. - - -!!! error TS-1: Pre-emit (11) and post-emit (13) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here! @@ -24,26 +28,35 @@ -!!! related TS7012 templateInsideCallback.js:29:5: This overload implicitly returns the type 'any' because it lacks a return type annotation. -!!! related TS7012 templateInsideCallback.js:37:5: This overload implicitly returns the type 'any' because it lacks a return type annotation. -==== templateInsideCallback.js (11 errors) ==== ++templateInsideCallback.js(40,14): error TS2304: Cannot find name 'T'. + + -+==== templateInsideCallback.js (10 errors) ==== ++==== templateInsideCallback.js (19 errors) ==== /** * @typedef Oops - ~~~~ -!!! error TS8021: JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags. * @template T ++ ~~~~~~~~ ++!!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag * @property {T} a ++ ~ ++!!! error TS2304: Cannot find name 'T'. * @property {T} b -@@= skipped -30, +22 lines =@@ - ~~~~~~~~ - !!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag - * @param {T} x -- ~ --!!! error TS2304: Cannot find name 'T'. ++ ~ ++!!! error TS2304: Cannot find name 'T'. + */ + /** + * @callback Call +@@= skipped -33, +40 lines =@@ + ~ + !!! error TS2304: Cannot find name 'T'. * @returns {T} ++ ~ ++!!! error TS2304: Cannot find name 'T'. */ /** -@@= skipped -9, +7 lines =@@ + * @template T * @type {Call} ~~~~~~~ !!! error TS2315: Type 'Call' is not generic. @@ -52,37 +65,32 @@ */ const identity = x => x; ~ -@@= skipped -18, +20 lines =@@ - - /** - * @overload -+ ~~~~~~~~ -+!!! error TS2394: This overload signature is not compatible with its implementation signature. -+!!! related TS2750 templateInsideCallback.js:47:10: The implementation signature is declared here. -+ ~~~~~~~~ -+!!! error TS7012: This overload implicitly returns the type 'any' because it lacks a return type annotation. - * @template T +@@= skipped -28, +32 lines =@@ ~~~~~~~~ !!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag * @template U ++ ~~~~~~~~ ++!!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag * @param {T[]} array -- ~ --!!! error TS2304: Cannot find name 'T'. + ~ + !!! error TS2304: Cannot find name 'T'. * @param {(x: T) => U[]} iterable -- ~ --!!! error TS2304: Cannot find name 'T'. + ~ + !!! error TS2304: Cannot find name 'T'. ++ ~ ++!!! error TS2304: Cannot find name 'U'. * @returns {U[]} ++ ~ ++!!! error TS2304: Cannot find name 'U'. */ /** * @overload -+ ~~~~~~~~ -+!!! error TS7012: This overload implicitly returns the type 'any' because it lacks a return type annotation. - * @template T - ~~~~~~~~ - !!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag - * @param {T[][]} array -- ~ --!!! error TS2304: Cannot find name 'T'. +@@= skipped -17, +23 lines =@@ + ~ + !!! error TS2304: Cannot find name 'T'. * @returns {T[]} ++ ~ ++!!! error TS2304: Cannot find name 'T'. */ - /** \ No newline at end of file + /** + * @param {unknown[]} array \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.js b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.js index 3df62cefd7e..dc6fe5579e0 100644 --- a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.js +++ b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.js @@ -113,7 +113,11 @@ function flatMap(array, iterable = identity) { //// [templateInsideCallback.d.ts] -type Call = () => any; +type Oops = { + a: T; + b: T; +}; +type Call = (x: T) => T; /** * @typedef Oops * @template T @@ -137,5 +141,5 @@ type Nested = { noooooo: string; }; }; -declare function flatMap(): any; -declare function flatMap(): any; +declare function flatMap(array: T[], iterable: (x: T) => U[]): U[]; +declare function flatMap(array: T[][]): T[]; diff --git a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.types b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.types index c3d8c4e3064..836fe8db2e6 100644 --- a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.types +++ b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.types @@ -52,7 +52,7 @@ const identity = x => x; * @returns {unknown[]} */ function flatMap(array, iterable = identity) { ->flatMap : { (): any; (): any; } +>flatMap : { (array: T[], iterable: (x: T) => U[]): U[]; (array: T[][]): T[]; } >array : unknown[] >iterable : (x: unknown) => unknown >identity : any diff --git a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.types.diff b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.types.diff index 86460e76ae3..cb676cf864f 100644 --- a/testdata/baselines/reference/submodule/conformance/templateInsideCallback.types.diff +++ b/testdata/baselines/reference/submodule/conformance/templateInsideCallback.types.diff @@ -5,7 +5,7 @@ */ function flatMap(array, iterable = identity) { ->flatMap : { (): any; (): any; } -+>flatMap : { (): any; (): any; } ++>flatMap : { (array: T[], iterable: (x: T) => U[]): U[]; (array: T[][]): T[]; } >array : unknown[] >iterable : (x: unknown) => unknown >identity : any \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt.diff deleted file mode 100644 index 24a1d9bbd35..00000000000 --- a/testdata/baselines/reference/submoduleAccepted/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt.diff +++ /dev/null @@ -1,46 +0,0 @@ ---- old.contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt -+++ new.contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt -@@= skipped -0, +0 lines =@@ -- -+index.js(2,28): error TS2304: Cannot find name 'B'. -+index.js(2,42): error TS2304: Cannot find name 'A'. -+index.js(2,48): error TS2304: Cannot find name 'B'. -+index.js(2,67): error TS2304: Cannot find name 'B'. -+index.js(10,12): error TS2315: Type 'Funcs' is not generic. -+ -+ -+==== index.js (5 errors) ==== -+ /** -+ * @typedef {{ [K in keyof B]: { fn: (a: A, b: B) => void; thing: B[K]; } }} Funcs -+ ~ -+!!! error TS2304: Cannot find name 'B'. -+ ~ -+!!! error TS2304: Cannot find name 'A'. -+ ~ -+!!! error TS2304: Cannot find name 'B'. -+ ~ -+!!! error TS2304: Cannot find name 'B'. -+ * @template A -+ * @template {Record} B -+ */ -+ -+ /** -+ * @template A -+ * @template {Record} B -+ * @param {Funcs} fns -+ ~~~~~~~~~~~ -+!!! error TS2315: Type 'Funcs' is not generic. -+ * @returns {[A, B]} -+ */ -+ function foo(fns) { -+ return /** @type {any} */ (null); -+ } -+ -+ const result = foo({ -+ bar: { -+ fn: -+ /** @param {string} a */ -+ (a) => {}, -+ thing: "asd", -+ }, -+ }); \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types.diff b/testdata/baselines/reference/submoduleAccepted/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types.diff deleted file mode 100644 index 5983e6ea332..00000000000 --- a/testdata/baselines/reference/submoduleAccepted/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types.diff +++ /dev/null @@ -1,20 +0,0 @@ ---- old.contravariantOnlyInferenceFromAnnotatedFunctionJs.types -+++ new.contravariantOnlyInferenceFromAnnotatedFunctionJs.types -@@= skipped -14, +14 lines =@@ - */ - function foo(fns) { - >foo : >(fns: Funcs) => [A, B] -->fns : Funcs -+>fns : any - - return /** @type {any} */ (null); - >(null) : any - } - - const result = foo({ -->result : [string, { bar: string; }] -->foo({ bar: { fn: /** @param {string} a */ (a) => {}, thing: "asd", },}) : [string, { bar: string; }] -+>result : [any, Record] -+>foo({ bar: { fn: /** @param {string} a */ (a) => {}, thing: "asd", },}) : [any, Record] - >foo : >(fns: Funcs) => [A, B] - >{ bar: { fn: /** @param {string} a */ (a) => {}, thing: "asd", },} : { bar: { fn: (a: string) => void; thing: string; }; } diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/jsFileFunctionOverloads2.js.diff b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileFunctionOverloads2.js.diff index c2638040260..d9ef493ee34 100644 --- a/testdata/baselines/reference/submoduleAccepted/compiler/jsFileFunctionOverloads2.js.diff +++ b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileFunctionOverloads2.js.diff @@ -100,30 +100,4 @@ -declare function identity(x: T): T; +declare const identity: (x: T) => T; +declare function flatMap(array: T[], iterable: (x: T) => U[]): U[]; -+declare function flatMap(array: T[][]): T[]; -+ -+ -+//// [DtsFileErrors] -+ -+ -+dist/jsFileFunctionOverloads2.d.ts(11,33): error TS2304: Cannot find name 'T'. -+dist/jsFileFunctionOverloads2.d.ts(11,41): error TS2304: Cannot find name 'T'. -+ -+ -+==== dist/jsFileFunctionOverloads2.d.ts (2 errors) ==== -+ declare function getTypeName(x: number): 'number'; -+ declare function getTypeName(x: string): 'string'; -+ declare function getTypeName(x: boolean): 'boolean'; -+ /** -+ * @template T -+ * @param {T} x -+ * @returns {T} -+ */ -+ declare const identity: (x: T) => T; -+ declare function flatMap(array: T[], iterable: (x: T) => U[]): U[]; -+ declare function flatMap(array: T[][]): T[]; -+ ~ -+!!! error TS2304: Cannot find name 'T'. -+ ~ -+!!! error TS2304: Cannot find name 'T'. -+ \ No newline at end of file ++declare function flatMap(array: T[][]): T[]; \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/compiler/jsFileMethodOverloads2.js.diff b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileMethodOverloads2.js.diff index 00432ac168e..0bb8535fa1e 100644 --- a/testdata/baselines/reference/submoduleAccepted/compiler/jsFileMethodOverloads2.js.diff +++ b/testdata/baselines/reference/submoduleAccepted/compiler/jsFileMethodOverloads2.js.diff @@ -60,11 +60,4 @@ + getTypeName(this: Example): 'string'; /** * @template U - * @overload -@@= skipped -54, +54 lines =@@ - * @param {(y: T) => unknown} [fn] - * @returns {unknown} - */ -- transform(): T; -+ transform(): T; - } \ No newline at end of file + * @overload \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/conformance/templateInsideCallback.js.diff b/testdata/baselines/reference/submoduleAccepted/conformance/templateInsideCallback.js.diff index 9f249633b52..36f1f3216ee 100644 --- a/testdata/baselines/reference/submoduleAccepted/conformance/templateInsideCallback.js.diff +++ b/testdata/baselines/reference/submoduleAccepted/conformance/templateInsideCallback.js.diff @@ -20,15 +20,19 @@ - * @returns {T[]} - */ -declare function flatMap(): any; -+type Call = () => any; ++type Oops = { ++ a: T; ++ b: T; ++}; ++type Call = (x: T) => T; /** * @typedef Oops * @template T -@@= skipped -39, +24 lines =@@ +@@= skipped -39, +28 lines =@@ noooooo: string; }; }; -type Oops = any; -type Call = () => any; -+declare function flatMap(): any; -+declare function flatMap(): any; \ No newline at end of file ++declare function flatMap(array: T[], iterable: (x: T) => U[]): U[]; ++declare function flatMap(array: T[][]): T[]; \ No newline at end of file From 243a7a3ced2cb73efeb47fe48afe6d8a58b38635 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 27 May 2026 15:50:57 -0700 Subject: [PATCH 5/7] Update submoduleAccepted.txt --- testdata/submoduleAccepted.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/testdata/submoduleAccepted.txt b/testdata/submoduleAccepted.txt index c31d587519e..aec26c1b068 100644 --- a/testdata/submoduleAccepted.txt +++ b/testdata/submoduleAccepted.txt @@ -255,8 +255,6 @@ compiler/conflictingDeclarationsImportFromNamespace1.errors.txt.diff compiler/conflictingDeclarationsImportFromNamespace1.types.diff compiler/conflictingDeclarationsImportFromNamespace2.errors.txt.diff compiler/conflictingDeclarationsImportFromNamespace2.types.diff -compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.errors.txt.diff -compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types.diff ## more accurate types/symbols ## compiler/allowJscheckJsTypeParameterNoCrash.symbols.diff From 60d46cd3f1835278fd189f13888e6e1e0a800446 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 27 May 2026 15:51:04 -0700 Subject: [PATCH 6/7] Add regression test --- .../compiler/jsDocGenericOverloads.symbols | 55 ++++++++++++++++++ .../compiler/jsDocGenericOverloads.types | 58 +++++++++++++++++++ .../cases/compiler/jsDocGenericOverloads.ts | 44 ++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 testdata/baselines/reference/compiler/jsDocGenericOverloads.symbols create mode 100644 testdata/baselines/reference/compiler/jsDocGenericOverloads.types create mode 100644 testdata/tests/cases/compiler/jsDocGenericOverloads.ts diff --git a/testdata/baselines/reference/compiler/jsDocGenericOverloads.symbols b/testdata/baselines/reference/compiler/jsDocGenericOverloads.symbols new file mode 100644 index 00000000000..663c601fc51 --- /dev/null +++ b/testdata/baselines/reference/compiler/jsDocGenericOverloads.symbols @@ -0,0 +1,55 @@ +//// [tests/cases/compiler/jsDocGenericOverloads.ts] //// + +=== main.js === +const createElementC = /** +>createElementC : Symbol(createElementC, Decl(main.js, 0, 5)) + + * @template {keyof HTMLElementTagNameMap} T + * @param {T}t + * @param {NodeList|HTMLCollection=}c + * + * @overload + * @param {T}t + * @return {HTMLElementTagNameMap[T]} + * + * @overload + * @param {T}t + * @param {NodeList|HTMLCollection}c + * @return {HTMLElementTagNameMap[T]} + */(t, c) => { +>t : Symbol(t, Decl(main.js, 13, 5)) +>c : Symbol(c, Decl(main.js, 13, 7)) + + /* ... omitted for brevity ... */ return document.createElement(t) +>document.createElement : Symbol(Document.createElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>document : Symbol(document, Decl(lib.dom.d.ts, --, --)) +>createElement : Symbol(Document.createElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>t : Symbol(t, Decl(main.js, 13, 5)) + } + +/** + * @template {keyof HTMLElementTagNameMap} T + * @param {T}t + * @param {NodeList|HTMLCollection=}c + * + * @overload + * @param {T}t + * @return {HTMLElementTagNameMap[T]} + * + * @overload + * @param {T}t + * @param {NodeList|HTMLCollection}c + * @return {HTMLElementTagNameMap[T]} + */ +function createElementF(t, c) { +>createElementF : Symbol(createElementF, Decl(main.js, 22, 4), Decl(main.js, 26, 4), Decl(main.js, 15, 2)) +>t : Symbol(t, Decl(main.js, 31, 24)) +>c : Symbol(c, Decl(main.js, 31, 26)) + + /* ... omitted for brevity ... */ return document.createElement(t) +>document.createElement : Symbol(Document.createElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>document : Symbol(document, Decl(lib.dom.d.ts, --, --)) +>createElement : Symbol(Document.createElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>t : Symbol(t, Decl(main.js, 31, 24)) +} + diff --git a/testdata/baselines/reference/compiler/jsDocGenericOverloads.types b/testdata/baselines/reference/compiler/jsDocGenericOverloads.types new file mode 100644 index 00000000000..282ad336788 --- /dev/null +++ b/testdata/baselines/reference/compiler/jsDocGenericOverloads.types @@ -0,0 +1,58 @@ +//// [tests/cases/compiler/jsDocGenericOverloads.ts] //// + +=== main.js === +const createElementC = /** +>createElementC : (t: T, c?: (NodeList | HTMLCollection) | undefined) => HTMLElementTagNameMap[T] + + * @template {keyof HTMLElementTagNameMap} T + * @param {T}t + * @param {NodeList|HTMLCollection=}c + * + * @overload + * @param {T}t + * @return {HTMLElementTagNameMap[T]} + * + * @overload + * @param {T}t + * @param {NodeList|HTMLCollection}c + * @return {HTMLElementTagNameMap[T]} + */(t, c) => { +>(t, c) => { /* ... omitted for brevity ... */ return document.createElement(t) } : (t: T, c?: (NodeList | HTMLCollection) | undefined) => HTMLElementTagNameMap[T] +>t : T +>c : HTMLCollection | NodeList | undefined + + /* ... omitted for brevity ... */ return document.createElement(t) +>document.createElement(t) : HTMLElementTagNameMap[T] +>document.createElement : { (tagName: K, options?: ElementCreationOptions): HTMLElementTagNameMap[K]; (tagName: K, options?: ElementCreationOptions): HTMLElementDeprecatedTagNameMap[K]; (tagName: string, options?: ElementCreationOptions): HTMLElement; } +>document : Document +>createElement : { (tagName: K, options?: ElementCreationOptions): HTMLElementTagNameMap[K]; (tagName: K, options?: ElementCreationOptions): HTMLElementDeprecatedTagNameMap[K]; (tagName: string, options?: ElementCreationOptions): HTMLElement; } +>t : T + } + +/** + * @template {keyof HTMLElementTagNameMap} T + * @param {T}t + * @param {NodeList|HTMLCollection=}c + * + * @overload + * @param {T}t + * @return {HTMLElementTagNameMap[T]} + * + * @overload + * @param {T}t + * @param {NodeList|HTMLCollection}c + * @return {HTMLElementTagNameMap[T]} + */ +function createElementF(t, c) { +>createElementF : { (t: T_1): HTMLElementTagNameMap[T_1]; (t: T_1, c: NodeList | HTMLCollection): HTMLElementTagNameMap[T_1]; } +>t : T +>c : HTMLCollection | NodeList | undefined + + /* ... omitted for brevity ... */ return document.createElement(t) +>document.createElement(t) : HTMLElementTagNameMap[T] +>document.createElement : { (tagName: K, options?: ElementCreationOptions): HTMLElementTagNameMap[K]; (tagName: K, options?: ElementCreationOptions): HTMLElementDeprecatedTagNameMap[K]; (tagName: string, options?: ElementCreationOptions): HTMLElement; } +>document : Document +>createElement : { (tagName: K, options?: ElementCreationOptions): HTMLElementTagNameMap[K]; (tagName: K, options?: ElementCreationOptions): HTMLElementDeprecatedTagNameMap[K]; (tagName: string, options?: ElementCreationOptions): HTMLElement; } +>t : T +} + diff --git a/testdata/tests/cases/compiler/jsDocGenericOverloads.ts b/testdata/tests/cases/compiler/jsDocGenericOverloads.ts new file mode 100644 index 00000000000..3aec928200c --- /dev/null +++ b/testdata/tests/cases/compiler/jsDocGenericOverloads.ts @@ -0,0 +1,44 @@ +// @checkJs: true +// @noEmit: true + +// https://github.com/microsoft/typescript-go/issues/4037 + +// TS7 doesn't support overloads with arrow functions and function expressions, so the +// @overload tags are ignored in the const declaration below. + +// @filename: main.js + +const createElementC = /** + * @template {keyof HTMLElementTagNameMap} T + * @param {T}t + * @param {NodeList|HTMLCollection=}c + * + * @overload + * @param {T}t + * @return {HTMLElementTagNameMap[T]} + * + * @overload + * @param {T}t + * @param {NodeList|HTMLCollection}c + * @return {HTMLElementTagNameMap[T]} + */(t, c) => { + /* ... omitted for brevity ... */ return document.createElement(t) + } + +/** + * @template {keyof HTMLElementTagNameMap} T + * @param {T}t + * @param {NodeList|HTMLCollection=}c + * + * @overload + * @param {T}t + * @return {HTMLElementTagNameMap[T]} + * + * @overload + * @param {T}t + * @param {NodeList|HTMLCollection}c + * @return {HTMLElementTagNameMap[T]} + */ +function createElementF(t, c) { + /* ... omitted for brevity ... */ return document.createElement(t) +} From 2a5aedf01772dea10d9d9ef7127370a4f4536fb8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 29 May 2026 17:52:54 -0700 Subject: [PATCH 7/7] Add comment --- internal/parser/reparser.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/parser/reparser.go b/internal/parser/reparser.go index c99c83d406f..29a53e3c7ed 100644 --- a/internal/parser/reparser.go +++ b/internal/parser/reparser.go @@ -229,6 +229,8 @@ func (p *Parser) gatherTypeParameters(j *ast.Node, typedefOrCallback bool) *ast. endPos := -1 firstTemplate := true for _, tag := range j.AsJSDoc().Tags.Nodes { + // When a JSDoc comment contains an `@typedef` or `@callback` tag, `@template` type parameter + // declarations apply to the type being defined. if !typedefOrCallback && (ast.IsJSDocTypedefTag(tag) || ast.IsJSDocCallbackTag(tag)) { return nil }