@@ -401,6 +401,7 @@ namespace ts {
401
401
const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
402
402
const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
403
403
const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
404
+ const resolvingSignaturesArray = [resolvingSignature];
404
405
405
406
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
406
407
const jsObjectLiteralIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
@@ -15359,8 +15360,17 @@ namespace ts {
15359
15360
}
15360
15361
}
15361
15362
15362
- if (context.typeArguments) {
15363
- signatures = mapDefined(signatures, s => getJsxSignatureTypeArgumentInstantiation(s, context, isJs));
15363
+ const links = getNodeLinks(context);
15364
+ if (!links.resolvedSignatures) {
15365
+ links.resolvedSignatures = createMap();
15366
+ }
15367
+ const cacheKey = "" + getTypeId(valueType);
15368
+ if (links.resolvedSignatures.get(cacheKey) && links.resolvedSignatures.get(cacheKey) !== resolvingSignaturesArray) {
15369
+ signatures = links.resolvedSignatures.get(cacheKey);
15370
+ }
15371
+ else if (!links.resolvedSignatures.get(cacheKey)) {
15372
+ links.resolvedSignatures.set(cacheKey, resolvingSignaturesArray);
15373
+ links.resolvedSignatures.set(cacheKey, signatures = instantiateJsxSignatures(context, signatures));
15364
15374
}
15365
15375
15366
15376
return getUnionType(map(signatures, ctor ? t => getJsxPropsTypeFromClassType(t, isJs, context, /*reportErrors*/ false) : t => getJsxPropsTypeFromCallSignature(t, context)), UnionReduction.None);
@@ -16341,6 +16351,40 @@ namespace ts {
16341
16351
return undefined;
16342
16352
}
16343
16353
16354
+ function getInstantiatedJsxSignatures(openingLikeElement: JsxOpeningLikeElement, elementType: Type, reportErrors?: boolean) {
16355
+ const links = getNodeLinks(openingLikeElement);
16356
+ if (!links.resolvedSignatures) {
16357
+ links.resolvedSignatures = createMap();
16358
+ }
16359
+ const cacheKey = "" + getTypeId(elementType);
16360
+ if (links.resolvedSignatures.get(cacheKey) && links.resolvedSignatures.get(cacheKey) === resolvingSignaturesArray) {
16361
+ return;
16362
+ }
16363
+ else if (links.resolvedSignatures.get(cacheKey)) {
16364
+ return links.resolvedSignatures.get(cacheKey);
16365
+ }
16366
+
16367
+ links.resolvedSignatures.set(cacheKey, resolvingSignaturesArray);
16368
+ // Resolve the signatures, preferring constructor
16369
+ let signatures = getSignaturesOfType(elementType, SignatureKind.Construct);
16370
+ if (signatures.length === 0) {
16371
+ // No construct signatures, try call signatures
16372
+ signatures = getSignaturesOfType(elementType, SignatureKind.Call);
16373
+ if (signatures.length === 0) {
16374
+ // We found no signatures at all, which is an error
16375
+ if (reportErrors) {
16376
+ error(openingLikeElement.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(openingLikeElement.tagName));
16377
+ }
16378
+ return;
16379
+ }
16380
+ }
16381
+
16382
+ // Instantiate in context of source type
16383
+ const results = instantiateJsxSignatures(openingLikeElement, signatures);
16384
+ links.resolvedSignatures.set(cacheKey, results);
16385
+ return results;
16386
+ }
16387
+
16344
16388
/**
16345
16389
* Resolve attributes type of the given opening-like element. The attributes type is a type of attributes associated with the given elementType.
16346
16390
* For instance:
@@ -16403,20 +16447,10 @@ namespace ts {
16403
16447
16404
16448
// Get the element instance type (the result of newing or invoking this tag)
16405
16449
16406
- // Resolve the signatures, preferring constructor
16407
- let signatures = getSignaturesOfType(elementType, SignatureKind.Construct);
16408
- if (signatures.length === 0) {
16409
- // No construct signatures, try call signatures
16410
- signatures = getSignaturesOfType(elementType, SignatureKind.Call);
16411
- if (signatures.length === 0) {
16412
- // We found no signatures at all, which is an error
16413
- error(openingLikeElement.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(openingLikeElement.tagName));
16414
- return unknownType;
16415
- }
16450
+ const instantiatedSignatures = getInstantiatedJsxSignatures(openingLikeElement, elementType, /*reportErrors*/ true);
16451
+ if (!length(instantiatedSignatures)) {
16452
+ return unknownType;
16416
16453
}
16417
-
16418
- // Instantiate in context of source type
16419
- const instantiatedSignatures = instantiateJsxSignatures(openingLikeElement, signatures);
16420
16454
const elemInstanceType = getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
16421
16455
16422
16456
// If we should include all stateless attributes type, then get all attributes type from all stateless function signature.
@@ -18106,11 +18140,11 @@ namespace ts {
18106
18140
18107
18141
let typeArguments: NodeArray<TypeNode>;
18108
18142
18109
- if (!isDecorator && !isJsxOpeningOrSelfClosingElement ) {
18143
+ if (!isDecorator) {
18110
18144
typeArguments = (<CallExpression>node).typeArguments;
18111
18145
18112
18146
// We already perform checking on the type arguments on the class declaration itself.
18113
- if (isTaggedTemplate || (<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword) {
18147
+ if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || (<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword) {
18114
18148
forEach(typeArguments, checkSourceElement);
18115
18149
}
18116
18150
}
@@ -18699,30 +18733,6 @@ namespace ts {
18699
18733
*/
18700
18734
function getResolvedJsxStatelessFunctionSignature(openingLikeElement: JsxOpeningLikeElement, elementType: Type, candidatesOutArray: Signature[]): Signature | undefined {
18701
18735
Debug.assert(!(elementType.flags & TypeFlags.Union));
18702
- return resolveStatelessJsxOpeningLikeElement(openingLikeElement, elementType, candidatesOutArray);
18703
- }
18704
-
18705
- /**
18706
- * Try treating a given opening-like element as stateless function component and resolve a tagName to a function signature.
18707
- * @param openingLikeElement an JSX opening-like element we want to try resolve its stateless function if possible
18708
- * @param elementType a type of the opening-like JSX element, a result of resolving tagName in opening-like element.
18709
- * @param candidatesOutArray an array of signature to be filled in by the function. It is passed by signature help in the language service;
18710
- * the function will fill it up with appropriate candidate signatures
18711
- * @return a resolved signature if we can find function matching function signature through resolve call or a first signature in the list of functions.
18712
- * otherwise return undefined if tag-name of the opening-like element doesn't have call signatures
18713
- */
18714
- function resolveStatelessJsxOpeningLikeElement(openingLikeElement: JsxOpeningLikeElement, elementType: Type, candidatesOutArray: Signature[]): Signature | undefined {
18715
- // If this function is called from language service, elementType can be a union type. This is not possible if the function is called from compiler (see: resolveCustomJsxElementAttributesType)
18716
- if (elementType.flags & TypeFlags.Union) {
18717
- const types = (elementType as UnionType).types;
18718
- let result: Signature;
18719
- for (const type of types) {
18720
- result = result || resolveStatelessJsxOpeningLikeElement(openingLikeElement, type, candidatesOutArray);
18721
- }
18722
-
18723
- return result;
18724
- }
18725
-
18726
18736
const callSignatures = elementType && getSignaturesOfType(elementType, SignatureKind.Call);
18727
18737
if (callSignatures && callSignatures.length > 0) {
18728
18738
return resolveCall(openingLikeElement, callSignatures, candidatesOutArray);
@@ -18744,7 +18754,18 @@ namespace ts {
18744
18754
case SyntaxKind.JsxOpeningElement:
18745
18755
case SyntaxKind.JsxSelfClosingElement:
18746
18756
// This code-path is called by language service
18747
- return resolveStatelessJsxOpeningLikeElement(node, checkExpression(node.tagName), candidatesOutArray) || unknownSignature;
18757
+ const exprTypes = checkExpression(node.tagName);
18758
+ return forEachType(exprTypes, exprType => {
18759
+ const sfcResult = getResolvedJsxStatelessFunctionSignature(node, exprType, candidatesOutArray);
18760
+ if (sfcResult && sfcResult !== unknownSignature) {
18761
+ return sfcResult;
18762
+ }
18763
+ const sigs = getInstantiatedJsxSignatures(node, exprType);
18764
+ if (candidatesOutArray && length(sigs)) {
18765
+ candidatesOutArray.push(...sigs);
18766
+ }
18767
+ return length(sigs) ? sigs[0] : unknownSignature;
18768
+ }) || unknownSignature;
18748
18769
}
18749
18770
Debug.assertNever(node, "Branch in 'resolveSignature' should be unreachable.");
18750
18771
}
0 commit comments