@@ -297,7 +297,7 @@ func (c *Checker) elaborateJsxComponents(node *ast.Node, source *Type, target *T
297297 if ! ast .IsJsxSpreadAttribute (prop ) && ! isHyphenatedJsxName (prop .Name ().Text ()) {
298298 nameType := c .getStringLiteralType (prop .Name ().Text ())
299299 if nameType != nil && nameType .flags & TypeFlagsNever == 0 {
300- reportedError = c .elaborateElement (source , target , relation , prop .Name (), prop .Initializer (), nameType , nil , diagnosticOutput ) || reportedError
300+ reportedError = c .elaborateElement (source , target , relation , prop .Name (), prop .Initializer (), nameType , nil , nil , diagnosticOutput ) || reportedError
301301 }
302302 }
303303 }
@@ -326,13 +326,14 @@ func (c *Checker) elaborateJsxComponents(node *ast.Node, source *Type, target *T
326326 nonArrayLikeTargetParts = c .filterType (childrenTargetType , func (t * Type ) bool { return ! c .isArrayOrTupleLikeType (t ) })
327327 }
328328 var invalidTextDiagnostic * diagnostics.Message
329- getInvalidTextualChildDiagnostic := func () * diagnostics.Message {
329+ var invalidTextDiagnosticArgs []any
330+ getInvalidTextualChildDiagnostic := func () (* diagnostics.Message , []any ) {
330331 if invalidTextDiagnostic == nil {
331332 tagNameText := scanner .GetTextOfNode (node .Parent .TagName ())
332- diagnostic : = diagnostics .X_0_components_don_t_accept_text_as_child_elements_Text_in_JSX_has_the_type_string_but_the_expected_type_of_1_is_2
333- invalidTextDiagnostic = diagnostics . FormatMessage ( diagnostic , tagNameText , childrenPropName , c .TypeToString (childrenTargetType ))
333+ invalidTextDiagnostic = diagnostics .X_0_components_don_t_accept_text_as_child_elements_Text_in_JSX_has_the_type_string_but_the_expected_type_of_1_is_2
334+ invalidTextDiagnosticArgs = [] any { tagNameText , childrenPropName , c .TypeToString (childrenTargetType )}
334335 }
335- return invalidTextDiagnostic
336+ return invalidTextDiagnostic , invalidTextDiagnosticArgs
336337 }
337338 if moreThanOneRealChildren {
338339 if arrayLikeTargetParts != c .neverType {
@@ -350,7 +351,7 @@ func (c *Checker) elaborateJsxComponents(node *ast.Node, source *Type, target *T
350351 child := validChildren [0 ]
351352 e := c .getElaborationElementForJsxChild (child , childrenNameType , getInvalidTextualChildDiagnostic )
352353 if e .errorNode != nil {
353- reportedError = c .elaborateElement (source , target , relation , e .errorNode , e .innerExpression , e .nameType , e . errorMessage , diagnosticOutput ) || reportedError
354+ reportedError = c .elaborateElement (source , target , relation , e .errorNode , e .innerExpression , e .nameType , nil , e . createDiagnostic , diagnosticOutput ) || reportedError
354355 }
355356 } else if ! c .isTypeRelatedTo (c .getIndexedAccessType (source , childrenNameType ), childrenTargetType , relation ) {
356357 // arity mismatch
@@ -364,13 +365,13 @@ func (c *Checker) elaborateJsxComponents(node *ast.Node, source *Type, target *T
364365}
365366
366367type JsxElaborationElement struct {
367- errorNode * ast.Node
368- innerExpression * ast.Node
369- nameType * Type
370- errorMessage * diagnostics. Message
368+ errorNode * ast.Node
369+ innerExpression * ast.Node
370+ nameType * Type
371+ createDiagnostic func ( prop * ast. Node ) * ast. Diagnostic // Optional: creates a custom diagnostic for this element
371372}
372373
373- func (c * Checker ) generateJsxChildren (node * ast.Node , getInvalidTextDiagnostic func () * diagnostics.Message ) iter.Seq [JsxElaborationElement ] {
374+ func (c * Checker ) generateJsxChildren (node * ast.Node , getInvalidTextDiagnostic func () ( * diagnostics.Message , [] any ) ) iter.Seq [JsxElaborationElement ] {
374375 return func (yield func (JsxElaborationElement ) bool ) {
375376 memberOffset := 0
376377 for i , child := range node .Children ().Nodes {
@@ -387,7 +388,7 @@ func (c *Checker) generateJsxChildren(node *ast.Node, getInvalidTextDiagnostic f
387388 }
388389}
389390
390- func (c * Checker ) getElaborationElementForJsxChild (child * ast.Node , nameType * Type , getInvalidTextDiagnostic func () * diagnostics.Message ) JsxElaborationElement {
391+ func (c * Checker ) getElaborationElementForJsxChild (child * ast.Node , nameType * Type , getInvalidTextDiagnostic func () ( * diagnostics.Message , [] any ) ) JsxElaborationElement {
391392 switch child .Kind {
392393 case ast .KindJsxExpression :
393394 // child is of the type of the expression
@@ -398,7 +399,15 @@ func (c *Checker) getElaborationElementForJsxChild(child *ast.Node, nameType *Ty
398399 return JsxElaborationElement {}
399400 }
400401 // child is a string
401- return JsxElaborationElement {errorNode : child , innerExpression : nil , nameType : nameType , errorMessage : getInvalidTextDiagnostic ()}
402+ return JsxElaborationElement {
403+ errorNode : child ,
404+ innerExpression : nil ,
405+ nameType : nameType ,
406+ createDiagnostic : func (prop * ast.Node ) * ast.Diagnostic {
407+ errorMessage , errorArgs := getInvalidTextDiagnostic ()
408+ return NewDiagnosticForNode (prop , errorMessage , errorArgs ... )
409+ },
410+ }
402411 case ast .KindJsxElement , ast .KindJsxSelfClosingElement , ast .KindJsxFragment :
403412 // child is of type JSX.Element
404413 return JsxElaborationElement {errorNode : child , innerExpression : child , nameType : nameType }
@@ -448,18 +457,21 @@ func (c *Checker) elaborateIterableOrArrayLikeTargetElementwise(iterator iter.Se
448457 if next != nil {
449458 specificSource = c .checkExpressionForMutableLocationWithContextualType (next , sourcePropType )
450459 }
451- if c .exactOptionalPropertyTypes && c .isExactOptionalPropertyMismatch (specificSource , targetPropType ) {
460+ if e .createDiagnostic != nil {
461+ // Use the custom diagnostic factory if provided (e.g., for JSX text children with dynamic error messages)
462+ c .reportDiagnostic (e .createDiagnostic (prop ), diagnosticOutput )
463+ } else if c .exactOptionalPropertyTypes && c .isExactOptionalPropertyMismatch (specificSource , targetPropType ) {
452464 diag := createDiagnosticForNode (prop , diagnostics .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target , c .TypeToString (specificSource ), c .TypeToString (targetPropType ))
453465 c .reportDiagnostic (diag , diagnosticOutput )
454466 } else {
455467 targetIsOptional := propName != ast .InternalSymbolNameMissing && core .OrElse (c .getPropertyOfType (tupleOrArrayLikeTargetParts , propName ), c .unknownSymbol ).Flags & ast .SymbolFlagsOptional != 0
456468 sourceIsOptional := propName != ast .InternalSymbolNameMissing && core .OrElse (c .getPropertyOfType (source , propName ), c .unknownSymbol ).Flags & ast .SymbolFlagsOptional != 0
457469 targetPropType = c .removeMissingType (targetPropType , targetIsOptional )
458470 sourcePropType = c .removeMissingType (sourcePropType , targetIsOptional && sourceIsOptional )
459- result := c .checkTypeRelatedToEx (specificSource , targetPropType , relation , prop , e . errorMessage , diagnosticOutput )
471+ result := c .checkTypeRelatedToEx (specificSource , targetPropType , relation , prop , nil , diagnosticOutput )
460472 if result && specificSource != sourcePropType {
461473 // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType
462- c .checkTypeRelatedToEx (sourcePropType , targetPropType , relation , prop , e . errorMessage , diagnosticOutput )
474+ c .checkTypeRelatedToEx (sourcePropType , targetPropType , relation , prop , nil , diagnosticOutput )
463475 }
464476 }
465477 }
0 commit comments