@@ -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);
@@ -16743,8 +16755,8 @@ namespace ts {
16743
16755
return strictNullChecks ? filterType(type, isNotOptionalTypeMarker) : type;
16744
16756
}
16745
16757
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;
16748
16760
}
16749
16761
16750
16762
function getOptionalExpressionType(exprType: Type, expression: Expression) {
@@ -22811,7 +22823,7 @@ namespace ts {
22811
22823
function checkPropertyAccessChain(node: PropertyAccessChain) {
22812
22824
const leftType = checkExpression(node.expression);
22813
22825
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);
22815
22827
}
22816
22828
22817
22829
function checkQualifiedName(node: QualifiedName) {
@@ -23243,7 +23255,7 @@ namespace ts {
23243
23255
function checkElementAccessChain(node: ElementAccessChain) {
23244
23256
const exprType = checkExpression(node.expression);
23245
23257
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);
23247
23259
}
23248
23260
23249
23261
function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type): Type {
@@ -23348,7 +23360,7 @@ namespace ts {
23348
23360
// interface B extends A { (x: 'foo'): string }
23349
23361
// const b: B;
23350
23362
// 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 {
23352
23364
let lastParent: Node | undefined;
23353
23365
let lastSymbol: Symbol | undefined;
23354
23366
let cutoffIndex = 0;
@@ -23390,7 +23402,7 @@ namespace ts {
23390
23402
spliceIndex = index;
23391
23403
}
23392
23404
23393
- result.splice(spliceIndex, 0, isOptionalCall ? getOptionalCallSignature(signature) : signature);
23405
+ result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags ) : signature);
23394
23406
}
23395
23407
}
23396
23408
@@ -24056,7 +24068,7 @@ namespace ts {
24056
24068
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
24057
24069
}
24058
24070
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 {
24060
24072
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
24061
24073
const isDecorator = node.kind === SyntaxKind.Decorator;
24062
24074
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
@@ -24075,7 +24087,7 @@ namespace ts {
24075
24087
24076
24088
const candidates = candidatesOutArray || [];
24077
24089
// reorderCandidates fills up the candidates array directly
24078
- reorderCandidates(signatures, candidates, isOptionalCall );
24090
+ reorderCandidates(signatures, candidates, callChainFlags );
24079
24091
if (!candidates.length) {
24080
24092
if (reportErrors) {
24081
24093
diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
@@ -24462,22 +24474,25 @@ namespace ts {
24462
24474
const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
24463
24475
if (baseTypeNode) {
24464
24476
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 );
24466
24478
}
24467
24479
}
24468
24480
return resolveUntypedCall(node);
24469
24481
}
24470
24482
24471
- let isOptional: boolean ;
24483
+ let callChainFlags: SignatureFlags ;
24472
24484
let funcType = checkExpression(node.expression);
24473
24485
if (isCallChain(node)) {
24474
24486
const nonOptionalType = getOptionalExpressionType(funcType, node.expression);
24475
- isOptional = nonOptionalType !== funcType;
24487
+ callChainFlags = nonOptionalType === funcType ? SignatureFlags.None :
24488
+ isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain :
24489
+ SignatureFlags.IsInnerCallChain;
24476
24490
funcType = nonOptionalType;
24477
24491
}
24478
24492
else {
24479
- isOptional = false ;
24493
+ callChainFlags = SignatureFlags.None ;
24480
24494
}
24495
+
24481
24496
funcType = checkNonNullTypeWithReporter(
24482
24497
funcType,
24483
24498
node.expression,
@@ -24553,7 +24568,7 @@ namespace ts {
24553
24568
return resolveErrorCall(node);
24554
24569
}
24555
24570
24556
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, isOptional );
24571
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags );
24557
24572
}
24558
24573
24559
24574
function isGenericFunctionReturningFunction(signature: Signature) {
@@ -24624,7 +24639,7 @@ namespace ts {
24624
24639
return resolveErrorCall(node);
24625
24640
}
24626
24641
24627
- return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24642
+ return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24628
24643
}
24629
24644
24630
24645
// If expressionType's apparent type is an object type with no construct signatures but
@@ -24633,7 +24648,7 @@ namespace ts {
24633
24648
// operation is Any. It is an error to have a Void this type.
24634
24649
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
24635
24650
if (callSignatures.length) {
24636
- const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24651
+ const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24637
24652
if (!noImplicitAny) {
24638
24653
if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
24639
24654
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
@@ -24848,7 +24863,7 @@ namespace ts {
24848
24863
return resolveErrorCall(node);
24849
24864
}
24850
24865
24851
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24866
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24852
24867
}
24853
24868
24854
24869
/**
@@ -24911,7 +24926,7 @@ namespace ts {
24911
24926
return resolveErrorCall(node);
24912
24927
}
24913
24928
24914
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false , headMessage);
24929
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None , headMessage);
24915
24930
}
24916
24931
24917
24932
function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
@@ -24963,7 +24978,7 @@ namespace ts {
24963
24978
return resolveErrorCall(node);
24964
24979
}
24965
24980
24966
- return resolveCall(node, signatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24981
+ return resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlags.None );
24967
24982
}
24968
24983
24969
24984
/**
@@ -27436,6 +27451,20 @@ namespace ts {
27436
27451
}
27437
27452
}
27438
27453
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
+
27439
27468
/**
27440
27469
* Returns the type of an expression. Unlike checkExpression, this function is simply concerned
27441
27470
* with computing the type and may not fully check all contained sub-expressions for errors.
@@ -27447,21 +27476,10 @@ namespace ts {
27447
27476
// Optimize for the common case of a call to a function with a single non-generic call
27448
27477
// signature where we can just fetch the return type without checking the arguments.
27449
27478
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;
27465
27483
}
27466
27484
}
27467
27485
else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
@@ -36174,7 +36192,4 @@ namespace ts {
36174
36192
return !!(s.flags & SignatureFlags.HasLiteralTypes);
36175
36193
}
36176
36194
36177
- export function signatureIsOptionalCall(s: Signature) {
36178
- return !!(s.flags & SignatureFlags.IsOptionalCall);
36179
- }
36180
36195
}
0 commit comments