@@ -8691,14 +8691,23 @@ namespace ts {
86918691 return result;
86928692 }
86938693
8694- function getOptionalCallSignature(signature: Signature) {
8695- return signatureIsOptionalCall(signature) ? signature :
8696- (signature.optionalCallSignatureCache || (signature.optionalCallSignatureCache = createOptionalCallSignature(signature)));
8694+ function getOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags): Signature {
8695+ if ((signature.flags & SignatureFlags.CallChainFlags) === callChainFlags) {
8696+ return signature;
8697+ }
8698+ if (!signature.optionalCallSignatureCache) {
8699+ signature.optionalCallSignatureCache = {};
8700+ }
8701+ const key = callChainFlags === SignatureFlags.IsInnerCallChain ? "inner" : "outer";
8702+ return signature.optionalCallSignatureCache[key]
8703+ || (signature.optionalCallSignatureCache[key] = createOptionalCallSignature(signature, callChainFlags));
86978704 }
86988705
8699- function createOptionalCallSignature(signature: Signature) {
8706+ function createOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags) {
8707+ Debug.assert(callChainFlags === SignatureFlags.IsInnerCallChain || callChainFlags === SignatureFlags.IsOuterCallChain,
8708+ "An optional call signature can either be for an inner call chain or an outer call chain, but not both.");
87008709 const result = cloneSignature(signature);
8701- result.flags |= SignatureFlags.IsOptionalCall ;
8710+ result.flags |= callChainFlags ;
87028711 return result;
87038712 }
87048713
@@ -10313,9 +10322,12 @@ namespace ts {
1031310322 signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
1031410323 getReturnTypeFromAnnotation(signature.declaration!) ||
1031510324 (nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));
10316- if (signatureIsOptionalCall( signature) ) {
10325+ if (signature.flags & SignatureFlags.IsInnerCallChain ) {
1031710326 type = addOptionalTypeMarker(type);
1031810327 }
10328+ else if (signature.flags & SignatureFlags.IsOuterCallChain) {
10329+ type = getOptionalType(type);
10330+ }
1031910331 if (!popTypeResolution()) {
1032010332 if (signature.declaration) {
1032110333 const typeNode = getEffectiveReturnTypeNode(signature.declaration);
@@ -16767,8 +16779,8 @@ namespace ts {
1676716779 return strictNullChecks ? filterType(type, isNotOptionalTypeMarker) : type;
1676816780 }
1676916781
16770- function propagateOptionalTypeMarker(type: Type, wasOptional: boolean) {
16771- return wasOptional ? addOptionalTypeMarker(type) : type;
16782+ function propagateOptionalTypeMarker(type: Type, node: OptionalChain, wasOptional: boolean) {
16783+ return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) : type;
1677216784 }
1677316785
1677416786 function getOptionalExpressionType(exprType: Type, expression: Expression) {
@@ -22835,7 +22847,7 @@ namespace ts {
2283522847 function checkPropertyAccessChain(node: PropertyAccessChain) {
2283622848 const leftType = checkExpression(node.expression);
2283722849 const nonOptionalType = getOptionalExpressionType(leftType, node.expression);
22838- return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), nonOptionalType !== leftType);
22850+ return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), node, nonOptionalType !== leftType);
2283922851 }
2284022852
2284122853 function checkQualifiedName(node: QualifiedName) {
@@ -23267,7 +23279,7 @@ namespace ts {
2326723279 function checkElementAccessChain(node: ElementAccessChain) {
2326823280 const exprType = checkExpression(node.expression);
2326923281 const nonOptionalType = getOptionalExpressionType(exprType, node.expression);
23270- return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), nonOptionalType !== exprType);
23282+ return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), node, nonOptionalType !== exprType);
2327123283 }
2327223284
2327323285 function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type): Type {
@@ -23372,7 +23384,7 @@ namespace ts {
2337223384 // interface B extends A { (x: 'foo'): string }
2337323385 // const b: B;
2337423386 // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
23375- function reorderCandidates(signatures: readonly Signature[], result: Signature[], isOptionalCall: boolean ): void {
23387+ function reorderCandidates(signatures: readonly Signature[], result: Signature[], callChainFlags: SignatureFlags ): void {
2337623388 let lastParent: Node | undefined;
2337723389 let lastSymbol: Symbol | undefined;
2337823390 let cutoffIndex = 0;
@@ -23414,7 +23426,7 @@ namespace ts {
2341423426 spliceIndex = index;
2341523427 }
2341623428
23417- result.splice(spliceIndex, 0, isOptionalCall ? getOptionalCallSignature(signature) : signature);
23429+ result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags ) : signature);
2341823430 }
2341923431 }
2342023432
@@ -24080,7 +24092,7 @@ namespace ts {
2408024092 return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
2408124093 }
2408224094
24083- function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, isOptionalCall: boolean , fallbackError?: DiagnosticMessage): Signature {
24095+ function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags , fallbackError?: DiagnosticMessage): Signature {
2408424096 const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
2408524097 const isDecorator = node.kind === SyntaxKind.Decorator;
2408624098 const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
@@ -24099,7 +24111,7 @@ namespace ts {
2409924111
2410024112 const candidates = candidatesOutArray || [];
2410124113 // reorderCandidates fills up the candidates array directly
24102- reorderCandidates(signatures, candidates, isOptionalCall );
24114+ reorderCandidates(signatures, candidates, callChainFlags );
2410324115 if (!candidates.length) {
2410424116 if (reportErrors) {
2410524117 diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
@@ -24486,22 +24498,25 @@ namespace ts {
2448624498 const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
2448724499 if (baseTypeNode) {
2448824500 const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode);
24489- return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, /*isOptional*/ false );
24501+ return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, SignatureFlags.None );
2449024502 }
2449124503 }
2449224504 return resolveUntypedCall(node);
2449324505 }
2449424506
24495- let isOptional: boolean ;
24507+ let callChainFlags: SignatureFlags ;
2449624508 let funcType = checkExpression(node.expression);
2449724509 if (isCallChain(node)) {
2449824510 const nonOptionalType = getOptionalExpressionType(funcType, node.expression);
24499- isOptional = nonOptionalType !== funcType;
24511+ callChainFlags = nonOptionalType === funcType ? SignatureFlags.None :
24512+ isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain :
24513+ SignatureFlags.IsInnerCallChain;
2450024514 funcType = nonOptionalType;
2450124515 }
2450224516 else {
24503- isOptional = false ;
24517+ callChainFlags = SignatureFlags.None ;
2450424518 }
24519+
2450524520 funcType = checkNonNullTypeWithReporter(
2450624521 funcType,
2450724522 node.expression,
@@ -24577,7 +24592,7 @@ namespace ts {
2457724592 return resolveErrorCall(node);
2457824593 }
2457924594
24580- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, isOptional );
24595+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags );
2458124596 }
2458224597
2458324598 function isGenericFunctionReturningFunction(signature: Signature) {
@@ -24648,7 +24663,7 @@ namespace ts {
2464824663 return resolveErrorCall(node);
2464924664 }
2465024665
24651- return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24666+ return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
2465224667 }
2465324668
2465424669 // If expressionType's apparent type is an object type with no construct signatures but
@@ -24657,7 +24672,7 @@ namespace ts {
2465724672 // operation is Any. It is an error to have a Void this type.
2465824673 const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
2465924674 if (callSignatures.length) {
24660- const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24675+ const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
2466124676 if (!noImplicitAny) {
2466224677 if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
2466324678 error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
@@ -24872,7 +24887,7 @@ namespace ts {
2487224887 return resolveErrorCall(node);
2487324888 }
2487424889
24875- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24890+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
2487624891 }
2487724892
2487824893 /**
@@ -24935,7 +24950,7 @@ namespace ts {
2493524950 return resolveErrorCall(node);
2493624951 }
2493724952
24938- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false , headMessage);
24953+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None , headMessage);
2493924954 }
2494024955
2494124956 function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
@@ -24987,7 +25002,7 @@ namespace ts {
2498725002 return resolveErrorCall(node);
2498825003 }
2498925004
24990- return resolveCall(node, signatures, candidatesOutArray, checkMode, /*isOptional*/ false );
25005+ return resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlags.None );
2499125006 }
2499225007
2499325008 /**
@@ -27460,6 +27475,20 @@ namespace ts {
2746027475 }
2746127476 }
2746227477
27478+ function getReturnTypeOfSingleNonGenericCallSignature(funcType: Type) {
27479+ const signature = getSingleCallSignature(funcType);
27480+ if (signature && !signature.typeParameters) {
27481+ return getReturnTypeOfSignature(signature);
27482+ }
27483+ }
27484+
27485+ function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) {
27486+ const funcType = checkExpression(expr.expression);
27487+ const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
27488+ const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType);
27489+ return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType);
27490+ }
27491+
2746327492 /**
2746427493 * Returns the type of an expression. Unlike checkExpression, this function is simply concerned
2746527494 * with computing the type and may not fully check all contained sub-expressions for errors.
@@ -27471,21 +27500,10 @@ namespace ts {
2747127500 // Optimize for the common case of a call to a function with a single non-generic call
2747227501 // signature where we can just fetch the return type without checking the arguments.
2747327502 if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
27474- let isOptional: boolean;
27475- let funcType: Type;
27476- if (isCallChain(expr)) {
27477- funcType = checkExpression(expr.expression);
27478- const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
27479- isOptional = funcType !== nonOptionalType;
27480- funcType = checkNonNullType(nonOptionalType, expr.expression);
27481- }
27482- else {
27483- isOptional = false;
27484- funcType = checkNonNullExpression(expr.expression);
27485- }
27486- const signature = getSingleCallSignature(funcType);
27487- if (signature && !signature.typeParameters) {
27488- return propagateOptionalTypeMarker(getReturnTypeOfSignature(signature), isOptional);
27503+ const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) :
27504+ getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression));
27505+ if (type) {
27506+ return type;
2748927507 }
2749027508 }
2749127509 else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
@@ -36198,7 +36216,4 @@ namespace ts {
3619836216 return !!(s.flags & SignatureFlags.HasLiteralTypes);
3619936217 }
3620036218
36201- export function signatureIsOptionalCall(s: Signature) {
36202- return !!(s.flags & SignatureFlags.IsOptionalCall);
36203- }
3620436219}
0 commit comments