@@ -14660,7 +14660,7 @@ namespace ts {
1466014660 return mapType(valueType, t => getJsxSignaturesParameterTypes(t, isJs, node));
1466114661 }
1466214662
14663- function getJsxSignaturesParameterTypes(valueType: Type, isJs: boolean, context: Node ) {
14663+ function getJsxSignaturesParameterTypes(valueType: Type, isJs: boolean, context: JsxOpeningLikeElement ) {
1466414664 // If the elemType is a string type, we have to return anyType to prevent an error downstream as we will try to find construct or call signature of the type
1466514665 if (valueType.flags & TypeFlags.String) {
1466614666 return anyType;
@@ -14698,6 +14698,10 @@ namespace ts {
1469814698 }
1469914699 }
1470014700
14701+ if (context.typeArguments) {
14702+ signatures = mapDefined(signatures, s => getJsxSignatureTypeArgumentInstantiation(s, context, isJs));
14703+ }
14704+
1470114705 return getUnionType(map(signatures, ctor ? t => getJsxPropsTypeFromConstructSignature(t, isJs, context) : t => getJsxPropsTypeFromCallSignature(t, context)), UnionReduction.None);
1470214706 }
1470314707
@@ -15508,21 +15512,57 @@ namespace ts {
1550815512
1550915513 // Instantiate in context of source type
1551015514 const instantiatedSignatures = [];
15515+ let candidateForTypeArgumentError: Signature;
15516+ let hasTypeArgumentError: boolean = !!node.typeArguments;
1551115517 for (const signature of signatures) {
1551215518 if (signature.typeParameters) {
1551315519 const isJavascript = isInJavaScriptFile(node);
15514- const inferenceContext = createInferenceContext(signature.typeParameters, signature, /*flags*/ isJavascript ? InferenceFlags.AnyDefault : InferenceFlags.None);
15515- const typeArguments = inferJsxTypeArguments(signature, node, inferenceContext);
15516- instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments, isJavascript));
15520+ const typeArgumentInstantiated = getJsxSignatureTypeArgumentInstantiation(signature, node, isJavascript, /*reportErrors*/ false);
15521+ if (typeArgumentInstantiated) {
15522+ hasTypeArgumentError = false;
15523+ instantiatedSignatures.push(typeArgumentInstantiated);
15524+ }
15525+ else {
15526+ if (node.typeArguments && hasCorrectTypeArgumentArity(signature, node.typeArguments)) {
15527+ candidateForTypeArgumentError = signature;
15528+ }
15529+ const inferenceContext = createInferenceContext(signature.typeParameters, signature, /*flags*/ isJavascript ? InferenceFlags.AnyDefault : InferenceFlags.None);
15530+ const typeArguments = inferJsxTypeArguments(signature, node, inferenceContext);
15531+ instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments, isJavascript));
15532+ }
1551715533 }
1551815534 else {
1551915535 instantiatedSignatures.push(signature);
1552015536 }
1552115537 }
1552215538
15539+ if (node.typeArguments && hasTypeArgumentError) {
15540+ if (candidateForTypeArgumentError) {
15541+ checkTypeArguments(candidateForTypeArgumentError, node.typeArguments, /*reportErrors*/ true);
15542+ }
15543+ // Length check to avoid issuing an arity error on length=0, the "Type argument list cannot be empty" grammar error alone is fine
15544+ else if (node.typeArguments.length !== 0) {
15545+ diagnostics.add(getTypeArgumentArityError(node, signatures, node.typeArguments));
15546+ }
15547+ }
15548+
1552315549 return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
1552415550 }
1552515551
15552+ function getJsxSignatureTypeArgumentInstantiation(signature: Signature, node: JsxOpeningLikeElement, isJavascript: boolean, reportErrors?: boolean) {
15553+ if (!node.typeArguments) {
15554+ return;
15555+ }
15556+ if (!hasCorrectTypeArgumentArity(signature, node.typeArguments)) {
15557+ return;
15558+ }
15559+ const args = checkTypeArguments(signature, node.typeArguments, reportErrors);
15560+ if (!args) {
15561+ return;
15562+ }
15563+ return getSignatureInstantiation(signature, args, isJavascript);
15564+ }
15565+
1552615566 function getJsxNamespaceAt(location: Node) {
1552715567 const namespaceName = getJsxNamespace(location);
1552815568 const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false);
@@ -16784,13 +16824,7 @@ namespace ts {
1678416824 spreadArgIndex = getSpreadArgumentIndex(args);
1678516825 }
1678616826
16787- // If the user supplied type arguments, but the number of type arguments does not match
16788- // the declared number of type parameters, the call has an incorrect arity.
16789- const numTypeParameters = length(signature.typeParameters);
16790- const minTypeArgumentCount = getMinTypeArgumentCount(signature.typeParameters);
16791- const hasRightNumberOfTypeArgs = !typeArguments ||
16792- (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters);
16793- if (!hasRightNumberOfTypeArgs) {
16827+ if (!hasCorrectTypeArgumentArity(signature, typeArguments)) {
1679416828 return false;
1679516829 }
1679616830
@@ -16810,6 +16844,15 @@ namespace ts {
1681016844 return callIsIncomplete || hasEnoughArguments;
1681116845 }
1681216846
16847+ function hasCorrectTypeArgumentArity(signature: Signature, typeArguments: NodeArray<TypeNode> | undefined) {
16848+ // If the user supplied type arguments, but the number of type arguments does not match
16849+ // the declared number of type parameters, the call has an incorrect arity.
16850+ const numTypeParameters = length(signature.typeParameters);
16851+ const minTypeArgumentCount = getMinTypeArgumentCount(signature.typeParameters);
16852+ return !typeArguments ||
16853+ (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters);
16854+ }
16855+
1681316856 // If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
1681416857 function getSingleCallSignature(type: Type): Signature {
1681516858 if (type.flags & TypeFlags.Object) {
@@ -17371,6 +17414,17 @@ namespace ts {
1737117414 }
1737217415 }
1737317416
17417+ function getTypeArgumentArityError(node: Node, signatures: Signature[], typeArguments: NodeArray<TypeNode>) {
17418+ let min = Infinity;
17419+ let max = -Infinity;
17420+ for (const sig of signatures) {
17421+ min = Math.min(min, getMinTypeArgumentCount(sig.typeParameters));
17422+ max = Math.max(max, length(sig.typeParameters));
17423+ }
17424+ const paramCount = min === max ? min : min + "-" + max;
17425+ return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length);
17426+ }
17427+
1737417428 function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[], fallbackError?: DiagnosticMessage): Signature {
1737517429 const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
1737617430 const isDecorator = node.kind === SyntaxKind.Decorator;
@@ -17498,14 +17552,7 @@ namespace ts {
1749817552 checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression).typeArguments, /*reportErrors*/ true, fallbackError);
1749917553 }
1750017554 else if (typeArguments && every(signatures, sig => length(sig.typeParameters) !== typeArguments.length)) {
17501- let min = Number.POSITIVE_INFINITY;
17502- let max = Number.NEGATIVE_INFINITY;
17503- for (const sig of signatures) {
17504- min = Math.min(min, getMinTypeArgumentCount(sig.typeParameters));
17505- max = Math.max(max, length(sig.typeParameters));
17506- }
17507- const paramCount = min < max ? min + "-" + max : min;
17508- diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length));
17555+ diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments));
1750917556 }
1751017557 else if (args) {
1751117558 let min = Number.POSITIVE_INFINITY;
@@ -26722,6 +26769,7 @@ namespace ts {
2672226769 }
2672326770
2672426771 function checkGrammarJsxElement(node: JsxOpeningLikeElement) {
26772+ checkGrammarTypeArguments(node, node.typeArguments);
2672526773 const seen = createUnderscoreEscapedMap<boolean>();
2672626774
2672726775 for (const attr of node.attributes.properties) {
0 commit comments