Skip to content

Commit 4384c90

Browse files
committed
Support higher order inferences for constructor functions
1 parent b010010 commit 4384c90

File tree

1 file changed

+25
-9
lines changed

1 file changed

+25
-9
lines changed

src/compiler/checker.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8563,7 +8563,9 @@ namespace ts {
85638563
function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: ReadonlyArray<TypeParameter>): Signature {
85648564
const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript));
85658565
if (inferredTypeParameters) {
8566-
const returnSignature = getSingleCallSignature(getReturnTypeOfSignature(instantiatedSignature));
8566+
const returnType = getReturnTypeOfSignature(instantiatedSignature);
8567+
const returnSignature = getSingleSignature(returnType, SignatureKind.Call, /*allowMembers*/ false) ||
8568+
getSingleSignature(returnType, SignatureKind.Construct, /*allowMembers*/ false);
85678569
if (returnSignature) {
85688570
const newReturnSignature = cloneSignature(returnSignature);
85698571
newReturnSignature.typeParameters = inferredTypeParameters;
@@ -8639,7 +8641,8 @@ namespace ts {
86398641
// object type literal or interface (using the new keyword). Each way of declaring a constructor
86408642
// will result in a different declaration kind.
86418643
if (!signature.isolatedSignatureType) {
8642-
const isConstructor = signature.declaration!.kind === SyntaxKind.Constructor || signature.declaration!.kind === SyntaxKind.ConstructSignature; // TODO: GH#18217
8644+
const kind = signature.declaration ? signature.declaration.kind : SyntaxKind.Unknown;
8645+
const isConstructor = kind === SyntaxKind.Constructor || kind === SyntaxKind.ConstructSignature || kind === SyntaxKind.ConstructorType;
86438646
const type = createObjectType(ObjectFlags.Anonymous);
86448647
type.members = emptySymbols;
86458648
type.properties = emptyArray;
@@ -20421,11 +20424,19 @@ namespace ts {
2042120424

2042220425
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
2042320426
function getSingleCallSignature(type: Type): Signature | undefined {
20427+
return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false);
20428+
}
20429+
20430+
function getSingleSignature(type: Type, kind: SignatureKind, allowMembers: boolean): Signature | undefined {
2042420431
if (type.flags & TypeFlags.Object) {
2042520432
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
20426-
if (resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0 &&
20427-
resolved.properties.length === 0 && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
20428-
return resolved.callSignatures[0];
20433+
if (allowMembers || resolved.properties.length === 0 && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
20434+
if (kind === SignatureKind.Call && resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0) {
20435+
return resolved.callSignatures[0];
20436+
}
20437+
if (kind === SignatureKind.Construct && resolved.constructSignatures.length === 1 && resolved.callSignatures.length === 0) {
20438+
return resolved.constructSignatures[0];
20439+
}
2042920440
}
2043020441
}
2043120442
return undefined;
@@ -23760,15 +23771,17 @@ namespace ts {
2376023771

2376123772
function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration | QualifiedName, type: Type, checkMode?: CheckMode) {
2376223773
if (checkMode && checkMode & (CheckMode.Inferential | CheckMode.SkipGenericFunctions)) {
23763-
const signature = getSingleCallSignature(type);
23774+
const callSignature = getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ true);
23775+
const constructSignature = getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ true);
23776+
const signature = callSignature || constructSignature;
2376423777
if (signature && signature.typeParameters) {
2376523778
if (checkMode & CheckMode.SkipGenericFunctions) {
2376623779
skippedGenericFunction(node, checkMode);
2376723780
return anyFunctionType;
2376823781
}
2376923782
const contextualType = getApparentTypeOfContextualType(<Expression>node);
23770-
if (contextualType) {
23771-
const contextualSignature = getSingleCallSignature(getNonNullableType(contextualType));
23783+
if (contextualType && !isMixinConstructorType(contextualType)) {
23784+
const contextualSignature = getSingleSignature(getNonNullableType(contextualType), callSignature ? SignatureKind.Call : SignatureKind.Construct, /*allowMembers*/ false);
2377223785
if (contextualSignature && !contextualSignature.typeParameters) {
2377323786
const context = getInferenceContext(node)!;
2377423787
// We have an expression that is an argument of a generic function for which we are performing
@@ -23777,7 +23790,10 @@ namespace ts {
2377723790
// if the outer function returns a function type with a single non-generic call signature and
2377823791
// if some of the outer function type parameters have no inferences so far. If so, we can
2377923792
// potentially add inferred type parameters to the outer function return type.
23780-
const returnSignature = context.signature && getSingleCallSignature(getReturnTypeOfSignature(context.signature));
23793+
const returnType = context.signature && getReturnTypeOfSignature(context.signature);
23794+
const returnSignature = returnType && (
23795+
getSingleSignature(returnType, SignatureKind.Call, /*allowMembers*/ false) ||
23796+
getSingleSignature(returnType, SignatureKind.Construct, /*allowMembers*/ false));
2378123797
if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) {
2378223798
// Instantiate the signature with its own type parameters as type arguments, possibly
2378323799
// renaming the type parameters to ensure they have unique names.

0 commit comments

Comments
 (0)