diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index fb3c33c01b814..0732f7695d41c 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -3449,7 +3449,7 @@ func (c *Checker) checkFunctionOrMethodDeclaration(node *ast.Node) { c.checkSourceElement(body) c.checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, c.getReturnTypeFromAnnotation(node)) if node.FunctionLikeData().FullSignature != nil { - if c.getContextualCallSignature(c.getTypeFromTypeNode(node.FunctionLikeData().FullSignature), node) == nil { + if c.getContextualCallSignature(c.removeMissingOrUndefinedType(c.getTypeFromTypeNode(node.FunctionLikeData().FullSignature)), node) == nil { c.error(node.FunctionLikeData().FullSignature, diagnostics.A_JSDoc_type_tag_on_a_function_must_have_a_signature_with_the_correct_number_of_arguments) } } @@ -10233,7 +10233,7 @@ func (c *Checker) checkFunctionExpressionOrObjectLiteralMethod(node *ast.Node, c c.checkGrammarForGenerator(node) } if node.FunctionLikeData().FullSignature != nil { - if c.getContextualCallSignature(c.getTypeFromTypeNode(node.FunctionLikeData().FullSignature), node) == nil { + if c.getContextualCallSignature(c.removeMissingOrUndefinedType(c.getTypeFromTypeNode(node.FunctionLikeData().FullSignature)), node) == nil { c.error(node.FunctionLikeData().FullSignature, diagnostics.A_JSDoc_type_tag_on_a_function_must_have_a_signature_with_the_correct_number_of_arguments) } } @@ -20188,7 +20188,7 @@ func (c *Checker) getReturnTypeFromAnnotation(declaration *ast.Node) *Type { func (c *Checker) getSignatureOfFullSignatureType(node *ast.Node) *Signature { if ast.IsInJSFile(node) && (ast.IsFunctionDeclaration(node) || ast.IsMethodDeclaration(node) || ast.IsFunctionExpressionOrArrowFunction(node)) && node.FunctionLikeData().FullSignature != nil { - return c.getSingleCallSignature(c.getTypeFromTypeNode(node.FunctionLikeData().FullSignature)) + return c.getSingleCallSignature(c.removeMissingOrUndefinedType(c.getTypeFromTypeNode(node.FunctionLikeData().FullSignature))) } return nil } diff --git a/tsc/testdata/baselines/reference/compiler/jsdocOptionalMethodFullSignature.errors.txt b/tsc/testdata/baselines/reference/compiler/jsdocOptionalMethodFullSignature.errors.txt new file mode 100644 index 0000000000000..04781d1e0d8e9 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/jsdocOptionalMethodFullSignature.errors.txt @@ -0,0 +1,20 @@ +/a.js(10,12): error TS8030: A JSDoc '@type' tag on a function must have a signature with the correct number of arguments. + + +==== /a.js (1 errors) ==== + /** @typedef {{ method?: (s: string) => number }} Example */ + + const example = { + /** @type {Example['method']} */ + method(s) { + return s.length; + } + }; + + /** @type {Example['method']} */ + ~~~~~~~~~~~~~~~~~ +!!! error TS8030: A JSDoc '@type' tag on a function must have a signature with the correct number of arguments. + function tooManyParams(s, extra) { + return 0; + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/jsdocOptionalMethodFullSignature.symbols b/tsc/testdata/baselines/reference/compiler/jsdocOptionalMethodFullSignature.symbols new file mode 100644 index 0000000000000..918b548af9223 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/jsdocOptionalMethodFullSignature.symbols @@ -0,0 +1,29 @@ +//// [tests/cases/compiler/jsdocOptionalMethodFullSignature.ts] //// + +=== /a.js === +/** @typedef {{ method?: (s: string) => number }} Example */ + +const example = { +>example : Symbol(example, Decl(a.js, 2, 5)) + + /** @type {Example['method']} */ + method(s) { +>method : Symbol(method, Decl(a.js, 2, 17)) +>s : Symbol(s, Decl(a.js, 4, 9)) + + return s.length; +>s.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>s : Symbol(s, Decl(a.js, 4, 9)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) + } +}; + +/** @type {Example['method']} */ +function tooManyParams(s, extra) { +>tooManyParams : Symbol(tooManyParams, Decl(a.js, 7, 2)) +>s : Symbol(s, Decl(a.js, 10, 23)) +>extra : Symbol(extra, Decl(a.js, 10, 25)) + + return 0; +} + diff --git a/tsc/testdata/baselines/reference/compiler/jsdocOptionalMethodFullSignature.types b/tsc/testdata/baselines/reference/compiler/jsdocOptionalMethodFullSignature.types new file mode 100644 index 0000000000000..51186de351988 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/jsdocOptionalMethodFullSignature.types @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/jsdocOptionalMethodFullSignature.ts] //// + +=== /a.js === +/** @typedef {{ method?: (s: string) => number }} Example */ + +const example = { +>example : { method(s: string): number; } +>{ /** @type {Example['method']} */ method(s) { return s.length; }} : { method(s: string): number; } + + /** @type {Example['method']} */ + method(s) { +>method : (s: string) => number +>s : string + + return s.length; +>s.length : number +>s : string +>length : number + } +}; + +/** @type {Example['method']} */ +function tooManyParams(s, extra) { +>tooManyParams : (s: string) => number +>s : string +>extra : any + + return 0; +>0 : 0 +} + diff --git a/tsc/testdata/tests/cases/compiler/jsdocOptionalMethodFullSignature.ts b/tsc/testdata/tests/cases/compiler/jsdocOptionalMethodFullSignature.ts new file mode 100644 index 0000000000000..2ab5f1ca0f298 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/jsdocOptionalMethodFullSignature.ts @@ -0,0 +1,19 @@ +// @target: es2015 +// @allowJs: true +// @checkJs: true +// @noEmit: true + +// @Filename: /a.js +/** @typedef {{ method?: (s: string) => number }} Example */ + +const example = { + /** @type {Example['method']} */ + method(s) { + return s.length; + } +}; + +/** @type {Example['method']} */ +function tooManyParams(s, extra) { + return 0; +}