@@ -8670,14 +8670,23 @@ namespace ts {
86708670 return result;
86718671 }
86728672
8673- function getOptionalCallSignature(signature: Signature) {
8674- return signatureIsOptionalCall(signature) ? signature :
8675- (signature.optionalCallSignatureCache || (signature.optionalCallSignatureCache = createOptionalCallSignature(signature)));
8673+ function getOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags): Signature {
8674+ if ((signature.flags & SignatureFlags.CallChainFlags) === callChainFlags) {
8675+ return signature;
8676+ }
8677+ if (!signature.optionalCallSignatureCache) {
8678+ signature.optionalCallSignatureCache = {};
8679+ }
8680+ const key = callChainFlags === SignatureFlags.IsInnerCallChain ? "inner" : "outer";
8681+ return signature.optionalCallSignatureCache[key]
8682+ || (signature.optionalCallSignatureCache[key] = createOptionalCallSignature(signature, callChainFlags));
86768683 }
86778684
8678- function createOptionalCallSignature(signature: Signature) {
8685+ function createOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags) {
8686+ Debug.assert(callChainFlags === SignatureFlags.IsInnerCallChain || callChainFlags === SignatureFlags.IsOuterCallChain,
8687+ "An optional call signature can either be for an inner call chain or an outer call chain, but not both.");
86798688 const result = cloneSignature(signature);
8680- result.flags |= SignatureFlags.IsOptionalCall ;
8689+ result.flags |= callChainFlags ;
86818690 return result;
86828691 }
86838692
@@ -10292,9 +10301,12 @@ namespace ts {
1029210301 signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
1029310302 getReturnTypeFromAnnotation(signature.declaration!) ||
1029410303 (nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));
10295- if (signatureIsOptionalCall( signature) ) {
10304+ if (signature.flags & SignatureFlags.IsInnerCallChain ) {
1029610305 type = addOptionalTypeMarker(type);
1029710306 }
10307+ else if (signature.flags & SignatureFlags.IsOuterCallChain) {
10308+ type = getOptionalType(type);
10309+ }
1029810310 if (!popTypeResolution()) {
1029910311 if (signature.declaration) {
1030010312 const typeNode = getEffectiveReturnTypeNode(signature.declaration);
@@ -16743,8 +16755,8 @@ namespace ts {
1674316755 return strictNullChecks ? filterType(type, isNotOptionalTypeMarker) : type;
1674416756 }
1674516757
16746- function propagateOptionalTypeMarker(type: Type, wasOptional: boolean) {
16747- return wasOptional ? addOptionalTypeMarker(type) : type;
16758+ function propagateOptionalTypeMarker(type: Type, node: OptionalChain, wasOptional: boolean) {
16759+ return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) : type;
1674816760 }
1674916761
1675016762 function getOptionalExpressionType(exprType: Type, expression: Expression) {
@@ -22811,7 +22823,7 @@ namespace ts {
2281122823 function checkPropertyAccessChain(node: PropertyAccessChain) {
2281222824 const leftType = checkExpression(node.expression);
2281322825 const nonOptionalType = getOptionalExpressionType(leftType, node.expression);
22814- return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), nonOptionalType !== leftType);
22826+ return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), node, nonOptionalType !== leftType);
2281522827 }
2281622828
2281722829 function checkQualifiedName(node: QualifiedName) {
@@ -23243,7 +23255,7 @@ namespace ts {
2324323255 function checkElementAccessChain(node: ElementAccessChain) {
2324423256 const exprType = checkExpression(node.expression);
2324523257 const nonOptionalType = getOptionalExpressionType(exprType, node.expression);
23246- return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), nonOptionalType !== exprType);
23258+ return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), node, nonOptionalType !== exprType);
2324723259 }
2324823260
2324923261 function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type): Type {
@@ -23348,7 +23360,7 @@ namespace ts {
2334823360 // interface B extends A { (x: 'foo'): string }
2334923361 // const b: B;
2335023362 // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
23351- function reorderCandidates(signatures: readonly Signature[], result: Signature[], isOptionalCall: boolean ): void {
23363+ function reorderCandidates(signatures: readonly Signature[], result: Signature[], callChainFlags: SignatureFlags ): void {
2335223364 let lastParent: Node | undefined;
2335323365 let lastSymbol: Symbol | undefined;
2335423366 let cutoffIndex = 0;
@@ -23390,7 +23402,7 @@ namespace ts {
2339023402 spliceIndex = index;
2339123403 }
2339223404
23393- result.splice(spliceIndex, 0, isOptionalCall ? getOptionalCallSignature(signature) : signature);
23405+ result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags ) : signature);
2339423406 }
2339523407 }
2339623408
@@ -24056,7 +24068,7 @@ namespace ts {
2405624068 return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
2405724069 }
2405824070
24059- function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, isOptionalCall: boolean , fallbackError?: DiagnosticMessage): Signature {
24071+ function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags , fallbackError?: DiagnosticMessage): Signature {
2406024072 const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
2406124073 const isDecorator = node.kind === SyntaxKind.Decorator;
2406224074 const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
@@ -24075,7 +24087,7 @@ namespace ts {
2407524087
2407624088 const candidates = candidatesOutArray || [];
2407724089 // reorderCandidates fills up the candidates array directly
24078- reorderCandidates(signatures, candidates, isOptionalCall );
24090+ reorderCandidates(signatures, candidates, callChainFlags );
2407924091 if (!candidates.length) {
2408024092 if (reportErrors) {
2408124093 diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
@@ -24462,22 +24474,25 @@ namespace ts {
2446224474 const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
2446324475 if (baseTypeNode) {
2446424476 const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode);
24465- return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, /*isOptional*/ false );
24477+ return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, SignatureFlags.None );
2446624478 }
2446724479 }
2446824480 return resolveUntypedCall(node);
2446924481 }
2447024482
24471- let isOptional: boolean ;
24483+ let callChainFlags: SignatureFlags ;
2447224484 let funcType = checkExpression(node.expression);
2447324485 if (isCallChain(node)) {
2447424486 const nonOptionalType = getOptionalExpressionType(funcType, node.expression);
24475- isOptional = nonOptionalType !== funcType;
24487+ callChainFlags = nonOptionalType === funcType ? SignatureFlags.None :
24488+ isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain :
24489+ SignatureFlags.IsInnerCallChain;
2447624490 funcType = nonOptionalType;
2447724491 }
2447824492 else {
24479- isOptional = false ;
24493+ callChainFlags = SignatureFlags.None ;
2448024494 }
24495+
2448124496 funcType = checkNonNullTypeWithReporter(
2448224497 funcType,
2448324498 node.expression,
@@ -24553,7 +24568,7 @@ namespace ts {
2455324568 return resolveErrorCall(node);
2455424569 }
2455524570
24556- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, isOptional );
24571+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags );
2455724572 }
2455824573
2455924574 function isGenericFunctionReturningFunction(signature: Signature) {
@@ -24624,7 +24639,7 @@ namespace ts {
2462424639 return resolveErrorCall(node);
2462524640 }
2462624641
24627- return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24642+ return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
2462824643 }
2462924644
2463024645 // If expressionType's apparent type is an object type with no construct signatures but
@@ -24633,7 +24648,7 @@ namespace ts {
2463324648 // operation is Any. It is an error to have a Void this type.
2463424649 const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
2463524650 if (callSignatures.length) {
24636- const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24651+ const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
2463724652 if (!noImplicitAny) {
2463824653 if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
2463924654 error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
@@ -24848,7 +24863,7 @@ namespace ts {
2484824863 return resolveErrorCall(node);
2484924864 }
2485024865
24851- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24866+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
2485224867 }
2485324868
2485424869 /**
@@ -24911,7 +24926,7 @@ namespace ts {
2491124926 return resolveErrorCall(node);
2491224927 }
2491324928
24914- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false , headMessage);
24929+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None , headMessage);
2491524930 }
2491624931
2491724932 function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
@@ -24963,7 +24978,7 @@ namespace ts {
2496324978 return resolveErrorCall(node);
2496424979 }
2496524980
24966- return resolveCall(node, signatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24981+ return resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlags.None );
2496724982 }
2496824983
2496924984 /**
@@ -27436,6 +27451,20 @@ namespace ts {
2743627451 }
2743727452 }
2743827453
27454+ function getReturnTypeOfSingleNonGenericCallSignature(funcType: Type) {
27455+ const signature = getSingleCallSignature(funcType);
27456+ if (signature && !signature.typeParameters) {
27457+ return getReturnTypeOfSignature(signature);
27458+ }
27459+ }
27460+
27461+ function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) {
27462+ const funcType = checkExpression(expr.expression);
27463+ const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
27464+ const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType);
27465+ return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType);
27466+ }
27467+
2743927468 /**
2744027469 * Returns the type of an expression. Unlike checkExpression, this function is simply concerned
2744127470 * with computing the type and may not fully check all contained sub-expressions for errors.
@@ -27447,21 +27476,10 @@ namespace ts {
2744727476 // Optimize for the common case of a call to a function with a single non-generic call
2744827477 // signature where we can just fetch the return type without checking the arguments.
2744927478 if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
27450- let isOptional: boolean;
27451- let funcType: Type;
27452- if (isCallChain(expr)) {
27453- funcType = checkExpression(expr.expression);
27454- const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
27455- isOptional = funcType !== nonOptionalType;
27456- funcType = checkNonNullType(nonOptionalType, expr.expression);
27457- }
27458- else {
27459- isOptional = false;
27460- funcType = checkNonNullExpression(expr.expression);
27461- }
27462- const signature = getSingleCallSignature(funcType);
27463- if (signature && !signature.typeParameters) {
27464- return propagateOptionalTypeMarker(getReturnTypeOfSignature(signature), isOptional);
27479+ const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) :
27480+ getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression));
27481+ if (type) {
27482+ return type;
2746527483 }
2746627484 }
2746727485 else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
@@ -36174,7 +36192,4 @@ namespace ts {
3617436192 return !!(s.flags & SignatureFlags.HasLiteralTypes);
3617536193 }
3617636194
36177- export function signatureIsOptionalCall(s: Signature) {
36178- return !!(s.flags & SignatureFlags.IsOptionalCall);
36179- }
3618036195}
0 commit comments