* Fixes #26128 - signature comp for jsdoc @class. Another issue caused by js functions tagged with jsdoc `@constructor` not having construct signatures. A jsdoc function type that constructs a type (`function(new: Ex)`), has a construct signature and return value inferred as the constructed type where as a jsdoc `@constructor` has no construct signatures, and it's call signature has a void return type (or undefined). i.e: ```javascript /** @constructor **/ function E() {}; // typeof E -> call signature: () => void /** @param {function(new: E)} d */ function c(d) {} // typeof d -> construct: () => E ``` -- This commit fixes this (in an inelegant way) by considering `@class` function signatures as construct signatures and synthesizing it's return value _only for signature comparison_. There might be a slight performance hit, since the synthesized return value is not cached; but changing the `@class` function's return type in `getReturnTypeOfSignature` causes other issues. * Update jsdoc function test to fix mistake.
This commit is contained in:
parent
cea4838972
commit
a1089893bd
|
@ -10744,11 +10744,13 @@ namespace ts {
|
|||
}
|
||||
|
||||
if (!ignoreReturnTypes) {
|
||||
const targetReturnType = getReturnTypeOfSignature(target);
|
||||
const targetReturnType = (target.declaration && isJavaScriptConstructor(target.declaration)) ?
|
||||
getJavaScriptClassType(target.declaration.symbol)! : getReturnTypeOfSignature(target);
|
||||
if (targetReturnType === voidType) {
|
||||
return result;
|
||||
}
|
||||
const sourceReturnType = getReturnTypeOfSignature(source);
|
||||
const sourceReturnType = (source.declaration && isJavaScriptConstructor(source.declaration)) ?
|
||||
getJavaScriptClassType(source.declaration.symbol)! : getReturnTypeOfSignature(source);
|
||||
|
||||
// The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
|
||||
const targetTypePredicate = getTypePredicateOfSignature(target);
|
||||
|
@ -12015,8 +12017,14 @@ namespace ts {
|
|||
return Ternary.True;
|
||||
}
|
||||
|
||||
const sourceSignatures = getSignaturesOfType(source, kind);
|
||||
const targetSignatures = getSignaturesOfType(target, kind);
|
||||
const sourceIsJSConstructor = source.symbol && isJavaScriptConstructor(source.symbol.valueDeclaration);
|
||||
const targetIsJSConstructor = target.symbol && isJavaScriptConstructor(target.symbol.valueDeclaration);
|
||||
|
||||
const sourceSignatures = getSignaturesOfType(source, (sourceIsJSConstructor && kind === SignatureKind.Construct) ?
|
||||
SignatureKind.Call : kind);
|
||||
const targetSignatures = getSignaturesOfType(target, (targetIsJSConstructor && kind === SignatureKind.Construct) ?
|
||||
SignatureKind.Call : kind);
|
||||
|
||||
if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length) {
|
||||
if (isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
|
||||
// An abstract constructor type is not assignable to a non-abstract constructor type
|
||||
|
|
76
tests/baselines/reference/jsdocFunctionType.errors.txt
Normal file
76
tests/baselines/reference/jsdocFunctionType.errors.txt
Normal file
|
@ -0,0 +1,76 @@
|
|||
tests/cases/conformance/jsdoc/functions.js(65,14): error TS2345: Argument of type 'typeof E' is not assignable to parameter of type 'new (arg1: number) => { length: number; }'.
|
||||
Type 'E' is not assignable to type '{ length: number; }'.
|
||||
Property 'length' is missing in type 'E'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/functions.js (1 errors) ====
|
||||
/**
|
||||
* @param {function(this: string, number): number} c is just passing on through
|
||||
* @return {function(this: string, number): number}
|
||||
*/
|
||||
function id1(c) {
|
||||
return c
|
||||
}
|
||||
|
||||
var x = id1(function (n) { return this.length + n });
|
||||
|
||||
/**
|
||||
* @param {function(new: { length: number }, number): number} c is just passing on through
|
||||
* @return {function(new: { length: number }, number): number}
|
||||
*/
|
||||
function id2(c) {
|
||||
return c
|
||||
}
|
||||
|
||||
class C {
|
||||
/** @param {number} n */
|
||||
constructor(n) {
|
||||
this.length = n;
|
||||
}
|
||||
}
|
||||
|
||||
var y = id2(C);
|
||||
var z = new y(12);
|
||||
z.length;
|
||||
|
||||
/** @type {function ("a" | "b", 1 | 2): 3 | 4} */
|
||||
var f = function (ab, onetwo) { return ab === "a" ? 3 : 4; }
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} n
|
||||
*/
|
||||
function D(n) {
|
||||
this.length = n;
|
||||
}
|
||||
|
||||
var y2 = id2(D);
|
||||
var z2 = new y2(33);
|
||||
z2.length;
|
||||
|
||||
|
||||
/**
|
||||
* @param {function(new: D, number)} dref
|
||||
* @return {D}
|
||||
*/
|
||||
var construct = function(dref) { return new dref(33); }
|
||||
var z3 = construct(D);
|
||||
z3.length;
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} n
|
||||
*/
|
||||
var E = function(n) {
|
||||
this.not_length_on_purpose = n;
|
||||
};
|
||||
|
||||
|
||||
var y3 = id2(E);
|
||||
~
|
||||
!!! error TS2345: Argument of type 'typeof E' is not assignable to parameter of type 'new (arg1: number) => { length: number; }'.
|
||||
!!! error TS2345: Type 'E' is not assignable to type '{ length: number; }'.
|
||||
!!! error TS2345: Property 'length' is missing in type 'E'.
|
||||
|
|
@ -68,3 +68,76 @@ var f = function (ab, onetwo) { return ab === "a" ? 3 : 4; }
|
|||
>onetwo : Symbol(onetwo, Decl(functions.js, 30, 21))
|
||||
>ab : Symbol(ab, Decl(functions.js, 30, 18))
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} n
|
||||
*/
|
||||
function D(n) {
|
||||
>D : Symbol(D, Decl(functions.js, 30, 61))
|
||||
>n : Symbol(n, Decl(functions.js, 37, 11))
|
||||
|
||||
this.length = n;
|
||||
>this.length : Symbol(D.length, Decl(functions.js, 37, 15))
|
||||
>this : Symbol(D, Decl(functions.js, 30, 61))
|
||||
>length : Symbol(D.length, Decl(functions.js, 37, 15))
|
||||
>n : Symbol(n, Decl(functions.js, 37, 11))
|
||||
}
|
||||
|
||||
var y2 = id2(D);
|
||||
>y2 : Symbol(y2, Decl(functions.js, 41, 3))
|
||||
>id2 : Symbol(id2, Decl(functions.js, 8, 53))
|
||||
>D : Symbol(D, Decl(functions.js, 30, 61))
|
||||
|
||||
var z2 = new y2(33);
|
||||
>z2 : Symbol(z2, Decl(functions.js, 42, 3))
|
||||
>y2 : Symbol(y2, Decl(functions.js, 41, 3))
|
||||
|
||||
z2.length;
|
||||
>z2.length : Symbol(length, Decl(functions.js, 12, 27))
|
||||
>z2 : Symbol(z2, Decl(functions.js, 42, 3))
|
||||
>length : Symbol(length, Decl(functions.js, 12, 27))
|
||||
|
||||
|
||||
/**
|
||||
* @param {function(new: D, number)} dref
|
||||
* @return {D}
|
||||
*/
|
||||
var construct = function(dref) { return new dref(33); }
|
||||
>construct : Symbol(construct, Decl(functions.js, 50, 3))
|
||||
>dref : Symbol(dref, Decl(functions.js, 50, 25))
|
||||
>dref : Symbol(dref, Decl(functions.js, 50, 25))
|
||||
|
||||
var z3 = construct(D);
|
||||
>z3 : Symbol(z3, Decl(functions.js, 51, 3))
|
||||
>construct : Symbol(construct, Decl(functions.js, 50, 3))
|
||||
>D : Symbol(D, Decl(functions.js, 30, 61))
|
||||
|
||||
z3.length;
|
||||
>z3.length : Symbol(D.length, Decl(functions.js, 37, 15))
|
||||
>z3 : Symbol(z3, Decl(functions.js, 51, 3))
|
||||
>length : Symbol(D.length, Decl(functions.js, 37, 15))
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} n
|
||||
*/
|
||||
var E = function(n) {
|
||||
>E : Symbol(E, Decl(functions.js, 59, 3))
|
||||
>n : Symbol(n, Decl(functions.js, 59, 17))
|
||||
|
||||
this.not_length_on_purpose = n;
|
||||
>this.not_length_on_purpose : Symbol(E.not_length_on_purpose, Decl(functions.js, 59, 21))
|
||||
>this : Symbol(E, Decl(functions.js, 59, 7))
|
||||
>not_length_on_purpose : Symbol(E.not_length_on_purpose, Decl(functions.js, 59, 21))
|
||||
>n : Symbol(n, Decl(functions.js, 59, 17))
|
||||
|
||||
};
|
||||
|
||||
|
||||
var y3 = id2(E);
|
||||
>y3 : Symbol(y3, Decl(functions.js, 64, 3))
|
||||
>id2 : Symbol(id2, Decl(functions.js, 8, 53))
|
||||
>E : Symbol(E, Decl(functions.js, 59, 3))
|
||||
|
||||
|
|
|
@ -81,3 +81,87 @@ var f = function (ab, onetwo) { return ab === "a" ? 3 : 4; }
|
|||
>3 : 3
|
||||
>4 : 4
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} n
|
||||
*/
|
||||
function D(n) {
|
||||
>D : typeof D
|
||||
>n : number
|
||||
|
||||
this.length = n;
|
||||
>this.length = n : number
|
||||
>this.length : number
|
||||
>this : D
|
||||
>length : number
|
||||
>n : number
|
||||
}
|
||||
|
||||
var y2 = id2(D);
|
||||
>y2 : new (arg1: number) => { length: number; }
|
||||
>id2(D) : new (arg1: number) => { length: number; }
|
||||
>id2 : (c: new (arg1: number) => { length: number; }) => new (arg1: number) => { length: number; }
|
||||
>D : typeof D
|
||||
|
||||
var z2 = new y2(33);
|
||||
>z2 : { length: number; }
|
||||
>new y2(33) : { length: number; }
|
||||
>y2 : new (arg1: number) => { length: number; }
|
||||
>33 : 33
|
||||
|
||||
z2.length;
|
||||
>z2.length : number
|
||||
>z2 : { length: number; }
|
||||
>length : number
|
||||
|
||||
|
||||
/**
|
||||
* @param {function(new: D, number)} dref
|
||||
* @return {D}
|
||||
*/
|
||||
var construct = function(dref) { return new dref(33); }
|
||||
>construct : (dref: new (arg1: number) => D) => D
|
||||
>function(dref) { return new dref(33); } : (dref: new (arg1: number) => D) => D
|
||||
>dref : new (arg1: number) => D
|
||||
>new dref(33) : D
|
||||
>dref : new (arg1: number) => D
|
||||
>33 : 33
|
||||
|
||||
var z3 = construct(D);
|
||||
>z3 : D
|
||||
>construct(D) : D
|
||||
>construct : (dref: new (arg1: number) => D) => D
|
||||
>D : typeof D
|
||||
|
||||
z3.length;
|
||||
>z3.length : number
|
||||
>z3 : D
|
||||
>length : number
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} n
|
||||
*/
|
||||
var E = function(n) {
|
||||
>E : typeof E
|
||||
>function(n) { this.not_length_on_purpose = n;} : typeof E
|
||||
>n : number
|
||||
|
||||
this.not_length_on_purpose = n;
|
||||
>this.not_length_on_purpose = n : number
|
||||
>this.not_length_on_purpose : number
|
||||
>this : E
|
||||
>not_length_on_purpose : number
|
||||
>n : number
|
||||
|
||||
};
|
||||
|
||||
|
||||
var y3 = id2(E);
|
||||
>y3 : new (arg1: number) => { length: number; }
|
||||
>id2(E) : new (arg1: number) => { length: number; }
|
||||
>id2 : (c: new (arg1: number) => { length: number; }) => new (arg1: number) => { length: number; }
|
||||
>E : typeof E
|
||||
|
||||
|
|
|
@ -36,3 +36,37 @@ z.length;
|
|||
|
||||
/** @type {function ("a" | "b", 1 | 2): 3 | 4} */
|
||||
var f = function (ab, onetwo) { return ab === "a" ? 3 : 4; }
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} n
|
||||
*/
|
||||
function D(n) {
|
||||
this.length = n;
|
||||
}
|
||||
|
||||
var y2 = id2(D);
|
||||
var z2 = new y2(33);
|
||||
z2.length;
|
||||
|
||||
|
||||
/**
|
||||
* @param {function(new: D, number)} dref
|
||||
* @return {D}
|
||||
*/
|
||||
var construct = function(dref) { return new dref(33); }
|
||||
var z3 = construct(D);
|
||||
z3.length;
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} n
|
||||
*/
|
||||
var E = function(n) {
|
||||
this.not_length_on_purpose = n;
|
||||
};
|
||||
|
||||
|
||||
var y3 = id2(E);
|
||||
|
|
Loading…
Reference in a new issue