@@ -401,6 +401,7 @@ namespace ts {
401401 const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
402402 const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
403403 const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
404+ const resolvingSignaturesArray = [resolvingSignature];
404405
405406 const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
406407 const jsObjectLiteralIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
@@ -15359,8 +15360,17 @@ namespace ts {
1535915360 }
1536015361 }
1536115362
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));
1536415374 }
1536515375
1536615376 return getUnionType(map(signatures, ctor ? t => getJsxPropsTypeFromClassType(t, isJs, context, /*reportErrors*/ false) : t => getJsxPropsTypeFromCallSignature(t, context)), UnionReduction.None);
@@ -16341,6 +16351,40 @@ namespace ts {
1634116351 return undefined;
1634216352 }
1634316353
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+
1634416388 /**
1634516389 * Resolve attributes type of the given opening-like element. The attributes type is a type of attributes associated with the given elementType.
1634616390 * For instance:
@@ -16403,20 +16447,10 @@ namespace ts {
1640316447
1640416448 // Get the element instance type (the result of newing or invoking this tag)
1640516449
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;
1641616453 }
16417-
16418- // Instantiate in context of source type
16419- const instantiatedSignatures = instantiateJsxSignatures(openingLikeElement, signatures);
1642016454 const elemInstanceType = getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
1642116455
1642216456 // If we should include all stateless attributes type, then get all attributes type from all stateless function signature.
@@ -18106,11 +18140,11 @@ namespace ts {
1810618140
1810718141 let typeArguments: NodeArray<TypeNode>;
1810818142
18109- if (!isDecorator && !isJsxOpeningOrSelfClosingElement ) {
18143+ if (!isDecorator) {
1811018144 typeArguments = (<CallExpression>node).typeArguments;
1811118145
1811218146 // 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) {
1811418148 forEach(typeArguments, checkSourceElement);
1811518149 }
1811618150 }
@@ -18699,30 +18733,6 @@ namespace ts {
1869918733 */
1870018734 function getResolvedJsxStatelessFunctionSignature(openingLikeElement: JsxOpeningLikeElement, elementType: Type, candidatesOutArray: Signature[]): Signature | undefined {
1870118735 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-
1872618736 const callSignatures = elementType && getSignaturesOfType(elementType, SignatureKind.Call);
1872718737 if (callSignatures && callSignatures.length > 0) {
1872818738 return resolveCall(openingLikeElement, callSignatures, candidatesOutArray);
@@ -18744,7 +18754,18 @@ namespace ts {
1874418754 case SyntaxKind.JsxOpeningElement:
1874518755 case SyntaxKind.JsxSelfClosingElement:
1874618756 // 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;
1874818769 }
1874918770 Debug.assertNever(node, "Branch in 'resolveSignature' should be unreachable.");
1875018771 }
0 commit comments