@@ -8691,14 +8691,23 @@ namespace ts {
8691
8691
return result;
8692
8692
}
8693
8693
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));
8697
8704
}
8698
8705
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.");
8700
8709
const result = cloneSignature(signature);
8701
- result.flags |= SignatureFlags.IsOptionalCall ;
8710
+ result.flags |= callChainFlags ;
8702
8711
return result;
8703
8712
}
8704
8713
@@ -10313,9 +10322,12 @@ namespace ts {
10313
10322
signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
10314
10323
getReturnTypeFromAnnotation(signature.declaration!) ||
10315
10324
(nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));
10316
- if (signatureIsOptionalCall( signature) ) {
10325
+ if (signature.flags & SignatureFlags.IsInnerCallChain ) {
10317
10326
type = addOptionalTypeMarker(type);
10318
10327
}
10328
+ else if (signature.flags & SignatureFlags.IsOuterCallChain) {
10329
+ type = getOptionalType(type);
10330
+ }
10319
10331
if (!popTypeResolution()) {
10320
10332
if (signature.declaration) {
10321
10333
const typeNode = getEffectiveReturnTypeNode(signature.declaration);
@@ -16767,8 +16779,8 @@ namespace ts {
16767
16779
return strictNullChecks ? filterType(type, isNotOptionalTypeMarker) : type;
16768
16780
}
16769
16781
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;
16772
16784
}
16773
16785
16774
16786
function getOptionalExpressionType(exprType: Type, expression: Expression) {
@@ -22835,7 +22847,7 @@ namespace ts {
22835
22847
function checkPropertyAccessChain(node: PropertyAccessChain) {
22836
22848
const leftType = checkExpression(node.expression);
22837
22849
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);
22839
22851
}
22840
22852
22841
22853
function checkQualifiedName(node: QualifiedName) {
@@ -23267,7 +23279,7 @@ namespace ts {
23267
23279
function checkElementAccessChain(node: ElementAccessChain) {
23268
23280
const exprType = checkExpression(node.expression);
23269
23281
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);
23271
23283
}
23272
23284
23273
23285
function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type): Type {
@@ -23372,7 +23384,7 @@ namespace ts {
23372
23384
// interface B extends A { (x: 'foo'): string }
23373
23385
// const b: B;
23374
23386
// 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 {
23376
23388
let lastParent: Node | undefined;
23377
23389
let lastSymbol: Symbol | undefined;
23378
23390
let cutoffIndex = 0;
@@ -23414,7 +23426,7 @@ namespace ts {
23414
23426
spliceIndex = index;
23415
23427
}
23416
23428
23417
- result.splice(spliceIndex, 0, isOptionalCall ? getOptionalCallSignature(signature) : signature);
23429
+ result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags ) : signature);
23418
23430
}
23419
23431
}
23420
23432
@@ -24080,7 +24092,7 @@ namespace ts {
24080
24092
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
24081
24093
}
24082
24094
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 {
24084
24096
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
24085
24097
const isDecorator = node.kind === SyntaxKind.Decorator;
24086
24098
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
@@ -24099,7 +24111,7 @@ namespace ts {
24099
24111
24100
24112
const candidates = candidatesOutArray || [];
24101
24113
// reorderCandidates fills up the candidates array directly
24102
- reorderCandidates(signatures, candidates, isOptionalCall );
24114
+ reorderCandidates(signatures, candidates, callChainFlags );
24103
24115
if (!candidates.length) {
24104
24116
if (reportErrors) {
24105
24117
diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
@@ -24486,22 +24498,25 @@ namespace ts {
24486
24498
const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
24487
24499
if (baseTypeNode) {
24488
24500
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 );
24490
24502
}
24491
24503
}
24492
24504
return resolveUntypedCall(node);
24493
24505
}
24494
24506
24495
- let isOptional: boolean ;
24507
+ let callChainFlags: SignatureFlags ;
24496
24508
let funcType = checkExpression(node.expression);
24497
24509
if (isCallChain(node)) {
24498
24510
const nonOptionalType = getOptionalExpressionType(funcType, node.expression);
24499
- isOptional = nonOptionalType !== funcType;
24511
+ callChainFlags = nonOptionalType === funcType ? SignatureFlags.None :
24512
+ isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain :
24513
+ SignatureFlags.IsInnerCallChain;
24500
24514
funcType = nonOptionalType;
24501
24515
}
24502
24516
else {
24503
- isOptional = false ;
24517
+ callChainFlags = SignatureFlags.None ;
24504
24518
}
24519
+
24505
24520
funcType = checkNonNullTypeWithReporter(
24506
24521
funcType,
24507
24522
node.expression,
@@ -24577,7 +24592,7 @@ namespace ts {
24577
24592
return resolveErrorCall(node);
24578
24593
}
24579
24594
24580
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, isOptional );
24595
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags );
24581
24596
}
24582
24597
24583
24598
function isGenericFunctionReturningFunction(signature: Signature) {
@@ -24648,7 +24663,7 @@ namespace ts {
24648
24663
return resolveErrorCall(node);
24649
24664
}
24650
24665
24651
- return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24666
+ return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24652
24667
}
24653
24668
24654
24669
// If expressionType's apparent type is an object type with no construct signatures but
@@ -24657,7 +24672,7 @@ namespace ts {
24657
24672
// operation is Any. It is an error to have a Void this type.
24658
24673
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
24659
24674
if (callSignatures.length) {
24660
- const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24675
+ const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24661
24676
if (!noImplicitAny) {
24662
24677
if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
24663
24678
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
@@ -24872,7 +24887,7 @@ namespace ts {
24872
24887
return resolveErrorCall(node);
24873
24888
}
24874
24889
24875
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24890
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24876
24891
}
24877
24892
24878
24893
/**
@@ -24935,7 +24950,7 @@ namespace ts {
24935
24950
return resolveErrorCall(node);
24936
24951
}
24937
24952
24938
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false , headMessage);
24953
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None , headMessage);
24939
24954
}
24940
24955
24941
24956
function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
@@ -24987,7 +25002,7 @@ namespace ts {
24987
25002
return resolveErrorCall(node);
24988
25003
}
24989
25004
24990
- return resolveCall(node, signatures, candidatesOutArray, checkMode, /*isOptional*/ false );
25005
+ return resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlags.None );
24991
25006
}
24992
25007
24993
25008
/**
@@ -27460,6 +27475,20 @@ namespace ts {
27460
27475
}
27461
27476
}
27462
27477
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
+
27463
27492
/**
27464
27493
* Returns the type of an expression. Unlike checkExpression, this function is simply concerned
27465
27494
* with computing the type and may not fully check all contained sub-expressions for errors.
@@ -27471,21 +27500,10 @@ namespace ts {
27471
27500
// Optimize for the common case of a call to a function with a single non-generic call
27472
27501
// signature where we can just fetch the return type without checking the arguments.
27473
27502
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;
27489
27507
}
27490
27508
}
27491
27509
else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
@@ -36198,7 +36216,4 @@ namespace ts {
36198
36216
return !!(s.flags & SignatureFlags.HasLiteralTypes);
36199
36217
}
36200
36218
36201
- export function signatureIsOptionalCall(s: Signature) {
36202
- return !!(s.flags & SignatureFlags.IsOptionalCall);
36203
- }
36204
36219
}
0 commit comments