Improve @overload's interactions with constructors (#52577)

This commit is contained in:
Nathan Shively-Sanders
2023-02-02 14:24:17 -08:00
committed by GitHub
parent 0f41b7a390
commit 0d251ba9bc
6 changed files with 306 additions and 1 deletions

View File

@@ -14458,7 +14458,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));
@@ -14584,6 +14584,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
}
@@ -33773,6 +33779,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)) {

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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))

View File

@@ -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

View File

@@ -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)