@@ -3291,7 +3291,7 @@ namespace ts {
3291
3291
if (symbol) {
3292
3292
const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class;
3293
3293
id = (isConstructorObject ? "+" : "") + getSymbolId(symbol);
3294
- if (isJavaScriptConstructor (symbol.valueDeclaration)) {
3294
+ if (isJavascriptConstructor (symbol.valueDeclaration)) {
3295
3295
// Instance and static types share the same symbol; only add 'typeof' for the static side.
3296
3296
const isInstanceType = type === getInferredClassType(symbol) ? SymbolFlags.Type : SymbolFlags.Value;
3297
3297
return symbolToTypeNode(symbol, context, isInstanceType);
@@ -5501,7 +5501,7 @@ namespace ts {
5501
5501
const constraint = getBaseConstraintOfType(type);
5502
5502
return !!constraint && isValidBaseType(constraint) && isMixinConstructorType(constraint);
5503
5503
}
5504
- return false ;
5504
+ return isJavascriptConstructorType(type) ;
5505
5505
}
5506
5506
5507
5507
function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments | undefined {
@@ -5510,9 +5510,12 @@ namespace ts {
5510
5510
5511
5511
function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray<TypeNode> | undefined, location: Node): ReadonlyArray<Signature> {
5512
5512
const typeArgCount = length(typeArgumentNodes);
5513
- const isJavaScript = isInJavaScriptFile(location);
5513
+ const isJavascript = isInJavaScriptFile(location);
5514
+ if (isJavascriptConstructorType(type) && !typeArgCount) {
5515
+ return getSignaturesOfType(type, SignatureKind.Call);
5516
+ }
5514
5517
return filter(getSignaturesOfType(type, SignatureKind.Construct),
5515
- sig => (isJavaScript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters));
5518
+ sig => (isJavascript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters));
5516
5519
}
5517
5520
5518
5521
function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray<TypeNode> | undefined, location: Node): ReadonlyArray<Signature> {
@@ -5603,6 +5606,9 @@ namespace ts {
5603
5606
else if (baseConstructorType.flags & TypeFlags.Any) {
5604
5607
baseType = baseConstructorType;
5605
5608
}
5609
+ else if (isJavascriptConstructorType(baseConstructorType) && !baseTypeNode.typeArguments) {
5610
+ baseType = getJavascriptClassType(baseConstructorType.symbol) || anyType;
5611
+ }
5606
5612
else {
5607
5613
// The class derives from a "class-like" constructor function, check that we have at least one construct signature
5608
5614
// with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere
@@ -10110,7 +10116,7 @@ namespace ts {
10110
10116
}
10111
10117
}
10112
10118
let outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true);
10113
- if (isJavaScriptConstructor (declaration)) {
10119
+ if (isJavascriptConstructor (declaration)) {
10114
10120
const templateTagParameters = getTypeParametersFromDeclaration(declaration as DeclarationWithTypeParameters);
10115
10121
outerTypeParameters = addRange(outerTypeParameters, templateTagParameters);
10116
10122
}
@@ -10407,7 +10413,7 @@ namespace ts {
10407
10413
function getTypeWithoutSignatures(type: Type): Type {
10408
10414
if (type.flags & TypeFlags.Object) {
10409
10415
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
10410
- if (resolved.constructSignatures.length) {
10416
+ if (resolved.constructSignatures.length || resolved.callSignatures.length ) {
10411
10417
const result = createObjectType(ObjectFlags.Anonymous, type.symbol);
10412
10418
result.members = resolved.members;
10413
10419
result.properties = resolved.properties;
@@ -10741,13 +10747,13 @@ namespace ts {
10741
10747
}
10742
10748
10743
10749
if (!ignoreReturnTypes) {
10744
- const targetReturnType = (target.declaration && isJavaScriptConstructor (target.declaration)) ?
10745
- getJavaScriptClassType (target.declaration.symbol)! : getReturnTypeOfSignature(target);
10750
+ const targetReturnType = (target.declaration && isJavascriptConstructor (target.declaration)) ?
10751
+ getJavascriptClassType (target.declaration.symbol)! : getReturnTypeOfSignature(target);
10746
10752
if (targetReturnType === voidType) {
10747
10753
return result;
10748
10754
}
10749
- const sourceReturnType = (source.declaration && isJavaScriptConstructor (source.declaration)) ?
10750
- getJavaScriptClassType (source.declaration.symbol)! : getReturnTypeOfSignature(source);
10755
+ const sourceReturnType = (source.declaration && isJavascriptConstructor (source.declaration)) ?
10756
+ getJavascriptClassType (source.declaration.symbol)! : getReturnTypeOfSignature(source);
10751
10757
10752
10758
// The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
10753
10759
const targetTypePredicate = getTypePredicateOfSignature(target);
@@ -12014,8 +12020,8 @@ namespace ts {
12014
12020
return Ternary.True;
12015
12021
}
12016
12022
12017
- const sourceIsJSConstructor = source.symbol && isJavaScriptConstructor (source.symbol.valueDeclaration);
12018
- const targetIsJSConstructor = target.symbol && isJavaScriptConstructor (target.symbol.valueDeclaration);
12023
+ const sourceIsJSConstructor = source.symbol && isJavascriptConstructor (source.symbol.valueDeclaration);
12024
+ const targetIsJSConstructor = target.symbol && isJavascriptConstructor (target.symbol.valueDeclaration);
12019
12025
12020
12026
const sourceSignatures = getSignaturesOfType(source, (sourceIsJSConstructor && kind === SignatureKind.Construct) ?
12021
12027
SignatureKind.Call : kind);
@@ -15500,7 +15506,7 @@ namespace ts {
15500
15506
// * /** @constructor */ var x = function() { ... }
15501
15507
else if ((container.kind === SyntaxKind.FunctionExpression || container.kind === SyntaxKind.FunctionDeclaration) &&
15502
15508
getJSDocClassTag(container)) {
15503
- const classType = getJavaScriptClassType (container.symbol);
15509
+ const classType = getJavascriptClassType (container.symbol);
15504
15510
if (classType) {
15505
15511
return getFlowTypeOfReference(node, classType);
15506
15512
}
@@ -19660,7 +19666,7 @@ namespace ts {
19660
19666
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
19661
19667
if (callSignatures.length) {
19662
19668
const signature = resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp);
19663
- if (signature.declaration && !isJavaScriptConstructor (signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
19669
+ if (signature.declaration && !isJavascriptConstructor (signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
19664
19670
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
19665
19671
}
19666
19672
if (getThisTypeOfSignature(signature) === voidType) {
@@ -19941,7 +19947,7 @@ namespace ts {
19941
19947
* Indicates whether a declaration can be treated as a constructor in a JavaScript
19942
19948
* file.
19943
19949
*/
19944
- function isJavaScriptConstructor (node: Declaration | undefined): boolean {
19950
+ function isJavascriptConstructor (node: Declaration | undefined): boolean {
19945
19951
if (node && isInJavaScriptFile(node)) {
19946
19952
// If the node has a @class tag, treat it like a constructor.
19947
19953
if (getJSDocClassTag(node)) return true;
@@ -19957,14 +19963,22 @@ namespace ts {
19957
19963
return false;
19958
19964
}
19959
19965
19960
- function getJavaScriptClassType(symbol: Symbol): Type | undefined {
19966
+ function isJavascriptConstructorType(type: Type) {
19967
+ if (type.flags & TypeFlags.Object) {
19968
+ const resolved = resolveStructuredTypeMembers(<ObjectType>type);
19969
+ return resolved.callSignatures.length === 1 && isJavascriptConstructor(resolved.callSignatures[0].declaration);
19970
+ }
19971
+ return false;
19972
+ }
19973
+
19974
+ function getJavascriptClassType(symbol: Symbol): Type | undefined {
19961
19975
let inferred: Type | undefined;
19962
- if (isJavaScriptConstructor (symbol.valueDeclaration)) {
19976
+ if (isJavascriptConstructor (symbol.valueDeclaration)) {
19963
19977
inferred = getInferredClassType(symbol);
19964
19978
}
19965
19979
const assigned = getAssignedClassType(symbol);
19966
19980
const valueType = getTypeOfSymbol(symbol);
19967
- if (valueType.symbol && !isInferredClassType(valueType) && isJavaScriptConstructor (valueType.symbol.valueDeclaration)) {
19981
+ if (valueType.symbol && !isInferredClassType(valueType) && isJavascriptConstructor (valueType.symbol.valueDeclaration)) {
19968
19982
inferred = getInferredClassType(valueType.symbol);
19969
19983
}
19970
19984
return assigned && inferred ?
@@ -20047,7 +20061,7 @@ namespace ts {
20047
20061
if (!funcSymbol && node.expression.kind === SyntaxKind.Identifier) {
20048
20062
funcSymbol = getResolvedSymbol(node.expression as Identifier);
20049
20063
}
20050
- const type = funcSymbol && getJavaScriptClassType (funcSymbol);
20064
+ const type = funcSymbol && getJavascriptClassType (funcSymbol);
20051
20065
if (type) {
20052
20066
return signature.target ? instantiateType(type, signature.mapper) : type;
20053
20067
}
@@ -20655,7 +20669,7 @@ namespace ts {
20655
20669
return undefined;
20656
20670
}
20657
20671
if (strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression &&
20658
- !(isJavaScriptConstructor (func) && aggregatedTypes.some(t => t.symbol === func.symbol))) {
20672
+ !(isJavascriptConstructor (func) && aggregatedTypes.some(t => t.symbol === func.symbol))) {
20659
20673
// Javascript "callable constructors", containing eg `if (!(this instanceof A)) return new A()` should not add undefined
20660
20674
pushIfUnique(aggregatedTypes, undefinedType);
20661
20675
}
@@ -25561,8 +25575,9 @@ namespace ts {
25561
25575
// that all instantiated base constructor signatures return the same type. We can simply compare the type
25562
25576
// references (as opposed to checking the structure of the types) because elsewhere we have already checked
25563
25577
// that the base type is a class or interface type (and not, for example, an anonymous object type).
25578
+ // (Javascript constructor functions have this property trivially true since their return type is ignored.)
25564
25579
const constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode);
25565
- if (forEach(constructors, sig => getReturnTypeOfSignature(sig) !== baseType)) {
25580
+ if (forEach(constructors, sig => !isJavascriptConstructor(sig.declaration) && getReturnTypeOfSignature(sig) !== baseType)) {
25566
25581
error(baseTypeNode.expression, Diagnostics.Base_constructors_must_all_have_the_same_return_type);
25567
25582
}
25568
25583
}
0 commit comments