@@ -8639,14 +8639,23 @@ namespace ts {
8639
8639
return result;
8640
8640
}
8641
8641
8642
- function getOptionalCallSignature(signature: Signature) {
8643
- return signatureIsOptionalCall(signature) ? signature :
8644
- (signature.optionalCallSignatureCache || (signature.optionalCallSignatureCache = createOptionalCallSignature(signature)));
8642
+ function getOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags): Signature {
8643
+ if ((signature.flags & SignatureFlags.CallChainFlags) === callChainFlags) {
8644
+ return signature;
8645
+ }
8646
+ if (!signature.optionalCallSignatureCache) {
8647
+ signature.optionalCallSignatureCache = {};
8648
+ }
8649
+ const key = callChainFlags === SignatureFlags.IsInnerCallChain ? "inner" : "outer";
8650
+ return signature.optionalCallSignatureCache[key]
8651
+ || (signature.optionalCallSignatureCache[key] = createOptionalCallSignature(signature, callChainFlags));
8645
8652
}
8646
8653
8647
- function createOptionalCallSignature(signature: Signature) {
8654
+ function createOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags) {
8655
+ Debug.assert(callChainFlags === SignatureFlags.IsInnerCallChain || callChainFlags === SignatureFlags.IsOuterCallChain,
8656
+ "An optional call signature can either be for an inner call chain or an outer call chain, but not both.");
8648
8657
const result = cloneSignature(signature);
8649
- result.flags |= SignatureFlags.IsOptionalCall ;
8658
+ result.flags |= callChainFlags ;
8650
8659
return result;
8651
8660
}
8652
8661
@@ -10261,9 +10270,12 @@ namespace ts {
10261
10270
signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
10262
10271
getReturnTypeFromAnnotation(signature.declaration!) ||
10263
10272
(nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));
10264
- if (signatureIsOptionalCall( signature) ) {
10273
+ if (signature.flags & SignatureFlags.IsInnerCallChain ) {
10265
10274
type = addOptionalTypeMarker(type);
10266
10275
}
10276
+ else if (signature.flags & SignatureFlags.IsOuterCallChain) {
10277
+ type = getOptionalType(type);
10278
+ }
10267
10279
if (!popTypeResolution()) {
10268
10280
if (signature.declaration) {
10269
10281
const typeNode = getEffectiveReturnTypeNode(signature.declaration);
@@ -16690,8 +16702,8 @@ namespace ts {
16690
16702
return strictNullChecks ? filterType(type, isNotOptionalTypeMarker) : type;
16691
16703
}
16692
16704
16693
- function propagateOptionalTypeMarker(type: Type, wasOptional: boolean) {
16694
- return wasOptional ? addOptionalTypeMarker(type) : type;
16705
+ function propagateOptionalTypeMarker(type: Type, node: OptionalChain, wasOptional: boolean) {
16706
+ return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) : type;
16695
16707
}
16696
16708
16697
16709
function getOptionalExpressionType(exprType: Type, expression: Expression) {
@@ -22730,7 +22742,7 @@ namespace ts {
22730
22742
function checkPropertyAccessChain(node: PropertyAccessChain) {
22731
22743
const leftType = checkExpression(node.expression);
22732
22744
const nonOptionalType = getOptionalExpressionType(leftType, node.expression);
22733
- return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), nonOptionalType !== leftType);
22745
+ return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), node, nonOptionalType !== leftType);
22734
22746
}
22735
22747
22736
22748
function checkQualifiedName(node: QualifiedName) {
@@ -23162,7 +23174,7 @@ namespace ts {
23162
23174
function checkElementAccessChain(node: ElementAccessChain) {
23163
23175
const exprType = checkExpression(node.expression);
23164
23176
const nonOptionalType = getOptionalExpressionType(exprType, node.expression);
23165
- return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), nonOptionalType !== exprType);
23177
+ return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), node, nonOptionalType !== exprType);
23166
23178
}
23167
23179
23168
23180
function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type): Type {
@@ -23267,7 +23279,7 @@ namespace ts {
23267
23279
// interface B extends A { (x: 'foo'): string }
23268
23280
// const b: B;
23269
23281
// b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
23270
- function reorderCandidates(signatures: readonly Signature[], result: Signature[], isOptionalCall: boolean ): void {
23282
+ function reorderCandidates(signatures: readonly Signature[], result: Signature[], callChainFlags: SignatureFlags ): void {
23271
23283
let lastParent: Node | undefined;
23272
23284
let lastSymbol: Symbol | undefined;
23273
23285
let cutoffIndex = 0;
@@ -23309,7 +23321,7 @@ namespace ts {
23309
23321
spliceIndex = index;
23310
23322
}
23311
23323
23312
- result.splice(spliceIndex, 0, isOptionalCall ? getOptionalCallSignature(signature) : signature);
23324
+ result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags ) : signature);
23313
23325
}
23314
23326
}
23315
23327
@@ -23975,7 +23987,7 @@ namespace ts {
23975
23987
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
23976
23988
}
23977
23989
23978
- function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, isOptionalCall: boolean , fallbackError?: DiagnosticMessage): Signature {
23990
+ function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags , fallbackError?: DiagnosticMessage): Signature {
23979
23991
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
23980
23992
const isDecorator = node.kind === SyntaxKind.Decorator;
23981
23993
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
@@ -23994,7 +24006,7 @@ namespace ts {
23994
24006
23995
24007
const candidates = candidatesOutArray || [];
23996
24008
// reorderCandidates fills up the candidates array directly
23997
- reorderCandidates(signatures, candidates, isOptionalCall );
24009
+ reorderCandidates(signatures, candidates, callChainFlags );
23998
24010
if (!candidates.length) {
23999
24011
if (reportErrors) {
24000
24012
diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
@@ -24381,22 +24393,25 @@ namespace ts {
24381
24393
const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
24382
24394
if (baseTypeNode) {
24383
24395
const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode);
24384
- return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, /*isOptional*/ false );
24396
+ return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, SignatureFlags.None );
24385
24397
}
24386
24398
}
24387
24399
return resolveUntypedCall(node);
24388
24400
}
24389
24401
24390
- let isOptional: boolean ;
24402
+ let callChainFlags: SignatureFlags ;
24391
24403
let funcType = checkExpression(node.expression);
24392
24404
if (isCallChain(node)) {
24393
24405
const nonOptionalType = getOptionalExpressionType(funcType, node.expression);
24394
- isOptional = nonOptionalType !== funcType;
24406
+ callChainFlags = nonOptionalType === funcType ? SignatureFlags.None :
24407
+ isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain :
24408
+ SignatureFlags.IsInnerCallChain;
24395
24409
funcType = nonOptionalType;
24396
24410
}
24397
24411
else {
24398
- isOptional = false ;
24412
+ callChainFlags = SignatureFlags.None ;
24399
24413
}
24414
+
24400
24415
funcType = checkNonNullTypeWithReporter(
24401
24416
funcType,
24402
24417
node.expression,
@@ -24472,7 +24487,7 @@ namespace ts {
24472
24487
return resolveErrorCall(node);
24473
24488
}
24474
24489
24475
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, isOptional );
24490
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags );
24476
24491
}
24477
24492
24478
24493
function isGenericFunctionReturningFunction(signature: Signature) {
@@ -24543,7 +24558,7 @@ namespace ts {
24543
24558
return resolveErrorCall(node);
24544
24559
}
24545
24560
24546
- return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24561
+ return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24547
24562
}
24548
24563
24549
24564
// If expressionType's apparent type is an object type with no construct signatures but
@@ -24552,7 +24567,7 @@ namespace ts {
24552
24567
// operation is Any. It is an error to have a Void this type.
24553
24568
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
24554
24569
if (callSignatures.length) {
24555
- const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24570
+ const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24556
24571
if (!noImplicitAny) {
24557
24572
if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
24558
24573
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
@@ -24767,7 +24782,7 @@ namespace ts {
24767
24782
return resolveErrorCall(node);
24768
24783
}
24769
24784
24770
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24785
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None );
24771
24786
}
24772
24787
24773
24788
/**
@@ -24830,7 +24845,7 @@ namespace ts {
24830
24845
return resolveErrorCall(node);
24831
24846
}
24832
24847
24833
- return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false , headMessage);
24848
+ return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None , headMessage);
24834
24849
}
24835
24850
24836
24851
function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
@@ -24882,7 +24897,7 @@ namespace ts {
24882
24897
return resolveErrorCall(node);
24883
24898
}
24884
24899
24885
- return resolveCall(node, signatures, candidatesOutArray, checkMode, /*isOptional*/ false );
24900
+ return resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlags.None );
24886
24901
}
24887
24902
24888
24903
/**
@@ -27355,6 +27370,20 @@ namespace ts {
27355
27370
}
27356
27371
}
27357
27372
27373
+ function getReturnTypeOfSingleNonGenericCallSignature(funcType: Type) {
27374
+ const signature = getSingleCallSignature(funcType);
27375
+ if (signature && !signature.typeParameters) {
27376
+ return getReturnTypeOfSignature(signature);
27377
+ }
27378
+ }
27379
+
27380
+ function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) {
27381
+ const funcType = checkExpression(expr.expression);
27382
+ const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
27383
+ const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType);
27384
+ return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType);
27385
+ }
27386
+
27358
27387
/**
27359
27388
* Returns the type of an expression. Unlike checkExpression, this function is simply concerned
27360
27389
* with computing the type and may not fully check all contained sub-expressions for errors.
@@ -27366,21 +27395,10 @@ namespace ts {
27366
27395
// Optimize for the common case of a call to a function with a single non-generic call
27367
27396
// signature where we can just fetch the return type without checking the arguments.
27368
27397
if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
27369
- let isOptional: boolean;
27370
- let funcType: Type;
27371
- if (isCallChain(expr)) {
27372
- funcType = checkExpression(expr.expression);
27373
- const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
27374
- isOptional = funcType !== nonOptionalType;
27375
- funcType = checkNonNullType(nonOptionalType, expr.expression);
27376
- }
27377
- else {
27378
- isOptional = false;
27379
- funcType = checkNonNullExpression(expr.expression);
27380
- }
27381
- const signature = getSingleCallSignature(funcType);
27382
- if (signature && !signature.typeParameters) {
27383
- return propagateOptionalTypeMarker(getReturnTypeOfSignature(signature), isOptional);
27398
+ const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) :
27399
+ getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression));
27400
+ if (type) {
27401
+ return type;
27384
27402
}
27385
27403
}
27386
27404
else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
@@ -36093,7 +36111,4 @@ namespace ts {
36093
36111
return !!(s.flags & SignatureFlags.HasLiteralTypes);
36094
36112
}
36095
36113
36096
- export function signatureIsOptionalCall(s: Signature) {
36097
- return !!(s.flags & SignatureFlags.IsOptionalCall);
36098
- }
36099
36114
}
0 commit comments