diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6370cd13625f3..472ecf1d888db 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14456,7 +14456,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const tag of node.tags) { if (isJSDocOverloadTag(tag)) { const jsDocSignature = tag.typeExpression; - if (jsDocSignature.type === undefined) { + if (jsDocSignature.type === undefined && !isConstructorDeclaration(decl)) { reportImplicitAny(jsDocSignature, anyType); } result.push(getSignatureFromDeclaration(jsDocSignature)); @@ -14582,6 +14582,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (declaration.kind === SyntaxKind.Constructor) { return getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent as ClassDeclaration).symbol)); } + if (isJSDocSignature(declaration)) { + const root = getJSDocRoot(declaration); + if (root && isConstructorDeclaration(root.parent)) { + return getDeclaredTypeOfClassOrInterface(getMergedSymbol((root.parent.parent as ClassDeclaration).symbol)); + } + } if (isJSDocConstructSignature(declaration)) { return getTypeFromTypeNode((declaration.parameters[0] as ParameterDeclaration).type!); // TODO: GH#18217 } @@ -33771,6 +33777,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { declaration.kind !== SyntaxKind.Constructor && declaration.kind !== SyntaxKind.ConstructSignature && declaration.kind !== SyntaxKind.ConstructorType && + !(isJSDocSignature(declaration) && getJSDocRoot(declaration)?.parent?.kind === SyntaxKind.Constructor) && !isJSDocConstructSignature(declaration) && !isJSConstructor(declaration)) { diff --git a/tests/baselines/reference/overloadTag2.errors.txt b/tests/baselines/reference/overloadTag2.errors.txt new file mode 100644 index 0000000000000..d6faad296ce71 --- /dev/null +++ b/tests/baselines/reference/overloadTag2.errors.txt @@ -0,0 +1,44 @@ +tests/cases/conformance/jsdoc/overloadTag2.js(25,20): error TS7006: Parameter 'b' implicitly has an 'any' type. +tests/cases/conformance/jsdoc/overloadTag2.js(30,9): error TS2554: Expected 1-2 arguments, but got 0. + + +==== tests/cases/conformance/jsdoc/overloadTag2.js (2 errors) ==== + export class Foo { + #a = true ? 1 : "1" + #b + + /** + * Should not have an implicit any error, because constructor's return type is always implicit + * @constructor + * @overload + * @param {string} a + * @param {number} b + */ + /** + * @constructor + * @overload + * @param {number} a + */ + /** + * @constructor + * @overload + * @param {string} a + *//** + * @constructor + * @param {number | string} a + */ + constructor(a, b) { + ~ +!!! error TS7006: Parameter 'b' implicitly has an 'any' type. + this.#a = a + this.#b = b + } + } + var a = new Foo() + ~~~~~~~~~ +!!! error TS2554: Expected 1-2 arguments, but got 0. +!!! related TS6210 tests/cases/conformance/jsdoc/overloadTag2.js:15:8: An argument for 'a' was not provided. + var b = new Foo('str') + var c = new Foo(2) + var d = new Foo('str', 2) + \ No newline at end of file diff --git a/tests/baselines/reference/overloadTag2.js b/tests/baselines/reference/overloadTag2.js new file mode 100644 index 0000000000000..04af61ffbbdb4 --- /dev/null +++ b/tests/baselines/reference/overloadTag2.js @@ -0,0 +1,78 @@ +//// [overloadTag2.js] +export class Foo { + #a = true ? 1 : "1" + #b + + /** + * Should not have an implicit any error, because constructor's return type is always implicit + * @constructor + * @overload + * @param {string} a + * @param {number} b + */ + /** + * @constructor + * @overload + * @param {number} a + */ + /** + * @constructor + * @overload + * @param {string} a + *//** + * @constructor + * @param {number | string} a + */ + constructor(a, b) { + this.#a = a + this.#b = b + } +} +var a = new Foo() +var b = new Foo('str') +var c = new Foo(2) +var d = new Foo('str', 2) + + +//// [overloadTag2.js] +export class Foo { + #a = true ? 1 : "1"; + #b; + /** + * Should not have an implicit any error, because constructor's return type is always implicit + * @constructor + * @overload + * @param {string} a + * @param {number} b + */ + /** + * @constructor + * @overload + * @param {number} a + */ + /** + * @constructor + * @overload + * @param {string} a + */ /** + * @constructor + * @param {number | string} a + */ + constructor(a, b) { + this.#a = a; + this.#b = b; + } +} +var a = new Foo(); +var b = new Foo('str'); +var c = new Foo(2); +var d = new Foo('str', 2); + + +//// [overloadTag2.d.ts] +export class Foo { + constructor(a: string, b: number); + constructor(a: number); + constructor(a: string); + #private; +} diff --git a/tests/baselines/reference/overloadTag2.symbols b/tests/baselines/reference/overloadTag2.symbols new file mode 100644 index 0000000000000..1e7bca466e87b --- /dev/null +++ b/tests/baselines/reference/overloadTag2.symbols @@ -0,0 +1,61 @@ +=== tests/cases/conformance/jsdoc/overloadTag2.js === +export class Foo { +>Foo : Symbol(Foo, Decl(overloadTag2.js, 0, 0)) + + #a = true ? 1 : "1" +>#a : Symbol(Foo.#a, Decl(overloadTag2.js, 0, 18)) + + #b +>#b : Symbol(Foo.#b, Decl(overloadTag2.js, 1, 23)) + + /** + * Should not have an implicit any error, because constructor's return type is always implicit + * @constructor + * @overload + * @param {string} a + * @param {number} b + */ + /** + * @constructor + * @overload + * @param {number} a + */ + /** + * @constructor + * @overload + * @param {string} a + *//** + * @constructor + * @param {number | string} a + */ + constructor(a, b) { +>a : Symbol(a, Decl(overloadTag2.js, 24, 16)) +>b : Symbol(b, Decl(overloadTag2.js, 24, 18)) + + this.#a = a +>this.#a : Symbol(Foo.#a, Decl(overloadTag2.js, 0, 18)) +>this : Symbol(Foo, Decl(overloadTag2.js, 0, 0)) +>a : Symbol(a, Decl(overloadTag2.js, 24, 16)) + + this.#b = b +>this.#b : Symbol(Foo.#b, Decl(overloadTag2.js, 1, 23)) +>this : Symbol(Foo, Decl(overloadTag2.js, 0, 0)) +>b : Symbol(b, Decl(overloadTag2.js, 24, 18)) + } +} +var a = new Foo() +>a : Symbol(a, Decl(overloadTag2.js, 29, 3)) +>Foo : Symbol(Foo, Decl(overloadTag2.js, 0, 0)) + +var b = new Foo('str') +>b : Symbol(b, Decl(overloadTag2.js, 30, 3)) +>Foo : Symbol(Foo, Decl(overloadTag2.js, 0, 0)) + +var c = new Foo(2) +>c : Symbol(c, Decl(overloadTag2.js, 31, 3)) +>Foo : Symbol(Foo, Decl(overloadTag2.js, 0, 0)) + +var d = new Foo('str', 2) +>d : Symbol(d, Decl(overloadTag2.js, 32, 3)) +>Foo : Symbol(Foo, Decl(overloadTag2.js, 0, 0)) + diff --git a/tests/baselines/reference/overloadTag2.types b/tests/baselines/reference/overloadTag2.types new file mode 100644 index 0000000000000..45fee2091e348 --- /dev/null +++ b/tests/baselines/reference/overloadTag2.types @@ -0,0 +1,75 @@ +=== tests/cases/conformance/jsdoc/overloadTag2.js === +export class Foo { +>Foo : Foo + + #a = true ? 1 : "1" +>#a : string | number +>true ? 1 : "1" : 1 | "1" +>true : true +>1 : 1 +>"1" : "1" + + #b +>#b : any + + /** + * Should not have an implicit any error, because constructor's return type is always implicit + * @constructor + * @overload + * @param {string} a + * @param {number} b + */ + /** + * @constructor + * @overload + * @param {number} a + */ + /** + * @constructor + * @overload + * @param {string} a + *//** + * @constructor + * @param {number | string} a + */ + constructor(a, b) { +>a : string | number +>b : any + + this.#a = a +>this.#a = a : string | number +>this.#a : string | number +>this : this +>a : string | number + + this.#b = b +>this.#b = b : any +>this.#b : any +>this : this +>b : any + } +} +var a = new Foo() +>a : Foo +>new Foo() : Foo +>Foo : typeof Foo + +var b = new Foo('str') +>b : Foo +>new Foo('str') : Foo +>Foo : typeof Foo +>'str' : "str" + +var c = new Foo(2) +>c : Foo +>new Foo(2) : Foo +>Foo : typeof Foo +>2 : 2 + +var d = new Foo('str', 2) +>d : Foo +>new Foo('str', 2) : Foo +>Foo : typeof Foo +>'str' : "str" +>2 : 2 + diff --git a/tests/cases/conformance/jsdoc/overloadTag2.ts b/tests/cases/conformance/jsdoc/overloadTag2.ts new file mode 100644 index 0000000000000..e6acf59b3800f --- /dev/null +++ b/tests/cases/conformance/jsdoc/overloadTag2.ts @@ -0,0 +1,40 @@ +// @checkJs: true +// @allowJs: true +// @target: esnext +// @outdir: foo +// @declaration: true +// @filename: overloadTag2.js +// @strict: true +export class Foo { + #a = true ? 1 : "1" + #b + + /** + * Should not have an implicit any error, because constructor's return type is always implicit + * @constructor + * @overload + * @param {string} a + * @param {number} b + */ + /** + * @constructor + * @overload + * @param {number} a + */ + /** + * @constructor + * @overload + * @param {string} a + *//** + * @constructor + * @param {number | string} a + */ + constructor(a, b) { + this.#a = a + this.#b = b + } +} +var a = new Foo() +var b = new Foo('str') +var c = new Foo(2) +var d = new Foo('str', 2)