@@ -8670,14 +8670,23 @@ namespace ts {
8670
8670
return result;
8671
8671
}
8672
8672
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));
8676
8683
}
8677
8684
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.");
8679
8688
const result = cloneSignature(signature);
8680
- result.flags |= SignatureFlags.IsOptionalCall ;
8689
+ result.flags |= callChainFlags ;
8681
8690
return result;
8682
8691
}
8683
8692
@@ -10292,9 +10301,12 @@ namespace ts {
10292
10301
signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
10293
10302
getReturnTypeFromAnnotation(signature.declaration!) ||
10294
10303
(nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));
10295
- if (signatureIsOptionalCall( signature) ) {
10304
+ if (signature.flags & SignatureFlags.IsInnerCallChain ) {
10296
10305
type = addOptionalTypeMarker(type);
10297
10306
}
10307
+ else if (signature.flags & SignatureFlags.IsOuterCallChain) {
10308
+ type = getOptionalType(type);
10309
+ }
10298
10310
if (!popTypeResolution()) {
10299
10311
if (signature.declaration) {
10300
10312
const typeNode = getEffectiveReturnTypeNode(signature.declaration);
@@ -16744,8 +16756,8 @@ namespace ts {
16744
16756
return strictNullChecks ? filterType(type, isNotOptionalTypeMarker) : type;
16745
16757
}
16746
16758
16747
- function propagateOptionalTypeMarker(type: Type, wasOptional: boolean) {
16748
- return wasOptional ? addOptionalTypeMarker(type) : type;
16759
+ function propagateOptionalTypeMarker(type: Type, node: OptionalChain, wasOptional: boolean) {
16760
+ return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) : type;
16749
16761
}
16750
16762
16751
16763
function getOptionalExpressionType(exprType: Type, expression: Expression) {
@@ -22812,7 +22824,7 @@ namespace ts {
22812
22824
function checkPropertyAccessChain(node: PropertyAccessChain) {
22813
22825
const leftType = checkExpression(node.expression);
22814
22826
const nonOptionalType = getOptionalExpressionType(leftType, node.expression);
22815
- return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), nonOptionalType !== leftType);
22827
+ return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), node, nonOptionalType !== leftType);
22816
22828
}
22817
22829
22818
22830
function checkQualifiedName(node: QualifiedName) {
@@ -23244,7 +23256,7 @@ namespace ts {
23244
23256
function checkElementAccessChain(node: ElementAccessChain) {
23245
23257
const exprType = checkExpression(node.expression);
23246
23258
const nonOptionalType = getOptionalExpressionType(exprType, node.expression);
23247
- return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), nonOptionalType !== exprType);
23259
+ return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), node, nonOptionalType !== exprType);
23248
23260
}
23249
23261
23250
23262
function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type): Type {
@@ -23349,7 +23361,7 @@ namespace ts {
23349
23361
// interface B extends A { (x: 'foo'): string }
23350
23362
// const b: B;
23351
23363
// b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
23352
- function reorderCandidates(signatures: readonly Signature[], result: Signature[], isOptionalCall: boolean ): void {
23364
+ function reorderCandidates(signatures: readonly Signature[], result: Signature[], callChainFlags: SignatureFlags ): void {
23353
23365
let lastParent: Node | undefined;
23354
23366
let lastSymbol: Symbol | undefined;
23355
23367
let cutoffIndex = 0;
@@ -23391,7 +23403,7 @@ namespace ts {
23391
23403
spliceIndex = index;
23392
23404
}
23393
23405
23394
- result.splice(spliceIndex, 0, isOptionalCall ? getOptionalCallSignature(signature) : signature);
23406
+ result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags ) : signature);
23395
23407
}
23396
23408
}
23397
23409
@@ -24057,7 +24069,7 @@ namespace ts {
24057
24069
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
24058
24070
}
24059
24071
24060
- function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, isOptionalCall: boolean , fallbackError?: DiagnosticMessage): Signature {
24072
+ function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags , fallbackError?: DiagnosticMessage): Signature {
24061
24073
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
24062
24074
const isDecorator = node.kind === SyntaxKind.Decorator;
24063
24075
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
@@ -24076,7 +24088,7 @@ namespace ts {
24076
24088
24077
24089
const candidates = candidatesOutArray || [];
24078
24090
// reorderCandidates fills up the candidates array directly
24079
- reorderCandidates(signatures, candidates, isOptionalCall );
24091
+ reorderCandidates(signatures, candidates, callChainFlags );
24080
24092
if (!candidates.length) {
24081
24093
if (reportErrors) {
24082
24094
diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
@@ -24463,22 +24475,25 @@ namespace ts {
24463
24475
const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
24464
24476
if (baseTypeNode) {
24465
24477
const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode);
24466
- return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, /*isOptional*/ false );
24478
+ return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, SignatureFlags.None );
24467
24479
}
24468
24480
}
24469
24481
return resolveUntypedCall(node);
24470
24482
}
24471
24483
24472
- let isOptional: boolean ;
24484
+ let callChainFlags: SignatureFlags ;
24473
24485
let funcType = checkExpression(node.expression);
24474
24486
if (isCallChain(node)) {
24475
24487
const nonOptionalType = getOptionalExpressionType(funcType, node.expression);
24476
- isOptional = nonOptionalType !== funcType;
24488
+ callChainFlags = nonOptionalType === funcType ? SignatureFlags.None :
24489
+ isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain :
24490
+ SignatureFlags.IsInnerCallChain;
24477
24491
funcType = nonOptionalType;
24478
24492
}
24479
24493
else {
24480
- isOptional = false ;
24494
+ callChainFlags = SignatureFlags.None ;
24481
24495
}
24496
+
24482
24497
funcType = checkNonNullTypeWithReporter(
24483
24498
funcType,
24484
24499
node.expression,
@@ -24554,7 +24569,7 @@ namespace ts {
24554
24569
return resolveErrorCall(node);
24555
24570
}
24556
24571
24557
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, isOptional );
24572
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags );
24558
24573
}
24559
24574
24560
24575
function isGenericFunctionReturningFunction(signature: Signature) {
@@ -24625,7 +24640,7 @@ namespace ts {
24625
24640
return resolveErrorCall(node);
24626
24641
}
24627
24642
24628
- return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24643
+ return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24629
24644
}
24630
24645
24631
24646
// If expressionType's apparent type is an object type with no construct signatures but
@@ -24634,7 +24649,7 @@ namespace ts {
24634
24649
// operation is Any. It is an error to have a Void this type.
24635
24650
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
24636
24651
if (callSignatures.length) {
24637
- const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24652
+ const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24638
24653
if (!noImplicitAny) {
24639
24654
if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
24640
24655
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
@@ -24849,7 +24864,7 @@ namespace ts {
24849
24864
return resolveErrorCall(node);
24850
24865
}
24851
24866
24852
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24867
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24853
24868
}
24854
24869
24855
24870
/**
@@ -24912,7 +24927,7 @@ namespace ts {
24912
24927
return resolveErrorCall(node);
24913
24928
}
24914
24929
24915
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false , headMessage);
24930
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None , headMessage);
24916
24931
}
24917
24932
24918
24933
function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
@@ -24964,7 +24979,7 @@ namespace ts {
24964
24979
return resolveErrorCall(node);
24965
24980
}
24966
24981
24967
- return resolveCall(node, signatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24982
+ return resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlags.None );
24968
24983
}
24969
24984
24970
24985
/**
@@ -27437,6 +27452,20 @@ namespace ts {
27437
27452
}
27438
27453
}
27439
27454
27455
+ function getReturnTypeOfSingleNonGenericCallSignature(funcType: Type) {
27456
+ const signature = getSingleCallSignature(funcType);
27457
+ if (signature && !signature.typeParameters) {
27458
+ return getReturnTypeOfSignature(signature);
27459
+ }
27460
+ }
27461
+
27462
+ function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) {
27463
+ const funcType = checkExpression(expr.expression);
27464
+ const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
27465
+ const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType);
27466
+ return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType);
27467
+ }
27468
+
27440
27469
/**
27441
27470
* Returns the type of an expression. Unlike checkExpression, this function is simply concerned
27442
27471
* with computing the type and may not fully check all contained sub-expressions for errors.
@@ -27448,21 +27477,10 @@ namespace ts {
27448
27477
// Optimize for the common case of a call to a function with a single non-generic call
27449
27478
// signature where we can just fetch the return type without checking the arguments.
27450
27479
if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
27451
- let isOptional: boolean;
27452
- let funcType: Type;
27453
- if (isCallChain(expr)) {
27454
- funcType = checkExpression(expr.expression);
27455
- const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
27456
- isOptional = funcType !== nonOptionalType;
27457
- funcType = checkNonNullType(nonOptionalType, expr.expression);
27458
- }
27459
- else {
27460
- isOptional = false;
27461
- funcType = checkNonNullExpression(expr.expression);
27462
- }
27463
- const signature = getSingleCallSignature(funcType);
27464
- if (signature && !signature.typeParameters) {
27465
- return propagateOptionalTypeMarker(getReturnTypeOfSignature(signature), isOptional);
27480
+ const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) :
27481
+ getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression));
27482
+ if (type) {
27483
+ return type;
27466
27484
}
27467
27485
}
27468
27486
else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
@@ -36175,7 +36193,4 @@ namespace ts {
36175
36193
return !!(s.flags & SignatureFlags.HasLiteralTypes);
36176
36194
}
36177
36195
36178
- export function signatureIsOptionalCall(s: Signature) {
36179
- return !!(s.flags & SignatureFlags.IsOptionalCall);
36180
- }
36181
36196
}
0 commit comments