@@ -14660,7 +14660,7 @@ namespace ts {
14660
14660
return mapType(valueType, t => getJsxSignaturesParameterTypes(t, isJs, node));
14661
14661
}
14662
14662
14663
- function getJsxSignaturesParameterTypes(valueType: Type, isJs: boolean, context: Node ) {
14663
+ function getJsxSignaturesParameterTypes(valueType: Type, isJs: boolean, context: JsxOpeningLikeElement ) {
14664
14664
// 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
14665
14665
if (valueType.flags & TypeFlags.String) {
14666
14666
return anyType;
@@ -14698,6 +14698,10 @@ namespace ts {
14698
14698
}
14699
14699
}
14700
14700
14701
+ if (context.typeArguments) {
14702
+ signatures = mapDefined(signatures, s => getJsxSignatureTypeArgumentInstantiation(s, context, isJs));
14703
+ }
14704
+
14701
14705
return getUnionType(map(signatures, ctor ? t => getJsxPropsTypeFromConstructSignature(t, isJs, context) : t => getJsxPropsTypeFromCallSignature(t, context)), UnionReduction.None);
14702
14706
}
14703
14707
@@ -15508,21 +15512,57 @@ namespace ts {
15508
15512
15509
15513
// Instantiate in context of source type
15510
15514
const instantiatedSignatures = [];
15515
+ let candidateForTypeArgumentError: Signature;
15516
+ let hasTypeArgumentError: boolean = !!node.typeArguments;
15511
15517
for (const signature of signatures) {
15512
15518
if (signature.typeParameters) {
15513
15519
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
+ }
15517
15533
}
15518
15534
else {
15519
15535
instantiatedSignatures.push(signature);
15520
15536
}
15521
15537
}
15522
15538
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
+
15523
15549
return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
15524
15550
}
15525
15551
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
+
15526
15566
function getJsxNamespaceAt(location: Node) {
15527
15567
const namespaceName = getJsxNamespace(location);
15528
15568
const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false);
@@ -16784,13 +16824,7 @@ namespace ts {
16784
16824
spreadArgIndex = getSpreadArgumentIndex(args);
16785
16825
}
16786
16826
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)) {
16794
16828
return false;
16795
16829
}
16796
16830
@@ -16810,6 +16844,15 @@ namespace ts {
16810
16844
return callIsIncomplete || hasEnoughArguments;
16811
16845
}
16812
16846
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
+
16813
16856
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
16814
16857
function getSingleCallSignature(type: Type): Signature {
16815
16858
if (type.flags & TypeFlags.Object) {
@@ -17371,6 +17414,17 @@ namespace ts {
17371
17414
}
17372
17415
}
17373
17416
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
+
17374
17428
function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[], fallbackError?: DiagnosticMessage): Signature {
17375
17429
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
17376
17430
const isDecorator = node.kind === SyntaxKind.Decorator;
@@ -17498,14 +17552,7 @@ namespace ts {
17498
17552
checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression).typeArguments, /*reportErrors*/ true, fallbackError);
17499
17553
}
17500
17554
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));
17509
17556
}
17510
17557
else if (args) {
17511
17558
let min = Number.POSITIVE_INFINITY;
@@ -26722,6 +26769,7 @@ namespace ts {
26722
26769
}
26723
26770
26724
26771
function checkGrammarJsxElement(node: JsxOpeningLikeElement) {
26772
+ checkGrammarTypeArguments(node, node.typeArguments);
26725
26773
const seen = createUnderscoreEscapedMap<boolean>();
26726
26774
26727
26775
for (const attr of node.attributes.properties) {
0 commit comments