@@ -9509,20 +9509,18 @@ namespace ts {
9509
9509
* element is not a class element, or the class element type cannot be determined, returns 'undefined'.
9510
9510
* For example, in the element <MyClass>, the element instance type is `MyClass` (not `typeof MyClass`).
9511
9511
*/
9512
- function getJsxElementInstanceType(node: JsxOpeningLikeElement) {
9513
- const valueType = checkExpression(node.tagName);
9514
-
9512
+ function getJsxElementInstanceType(node: JsxOpeningLikeElement, valueType: Type) {
9513
+ Debug.assert(!(valueType.flags & TypeFlags.Union));
9515
9514
if (isTypeAny(valueType)) {
9516
9515
// Short-circuit if the class tag is using an element type 'any'
9517
9516
return anyType;
9518
9517
}
9519
9518
9520
- // Resolve the signatures, preferring constructors
9519
+ // Resolve the signatures, preferring constructor
9521
9520
let signatures = getSignaturesOfType(valueType, SignatureKind.Construct);
9522
9521
if (signatures.length === 0) {
9523
9522
// No construct signatures, try call signatures
9524
9523
signatures = getSignaturesOfType(valueType, SignatureKind.Call);
9525
-
9526
9524
if (signatures.length === 0) {
9527
9525
// We found no signatures at all, which is an error
9528
9526
error(node.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node.tagName));
@@ -9570,6 +9568,103 @@ namespace ts {
9570
9568
}
9571
9569
}
9572
9570
9571
+ /**
9572
+ * Given React element instance type and the class type, resolve the Jsx type
9573
+ * Pass elemType to handle individual type in the union typed element type.
9574
+ */
9575
+ function getResolvedJsxType(node: JsxOpeningLikeElement, elemType?: Type, elemClassType?: Type): Type {
9576
+ if (!elemType) {
9577
+ elemType = checkExpression(node.tagName);
9578
+ }
9579
+ if (elemType.flags & TypeFlags.Union) {
9580
+ const types = (<UnionOrIntersectionType> elemType).types;
9581
+ return getUnionType(types.map(type => {
9582
+ return getResolvedJsxType(node, type, elemClassType);
9583
+ }));
9584
+ }
9585
+
9586
+ // Get the element instance type (the result of newing or invoking this tag)
9587
+ const elemInstanceType = getJsxElementInstanceType(node, elemType);
9588
+
9589
+ if (!elemClassType || !isTypeAssignableTo(elemInstanceType, elemClassType)) {
9590
+ // Is this is a stateless function component? See if its single signature's return type is
9591
+ // assignable to the JSX Element Type
9592
+ if (jsxElementType) {
9593
+ const callSignatures = elemType && getSignaturesOfType(elemType, SignatureKind.Call);
9594
+ const callSignature = callSignatures && callSignatures.length > 0 && callSignatures[0];
9595
+ const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
9596
+ let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0]));
9597
+ if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType)) {
9598
+ // Intersect in JSX.IntrinsicAttributes if it exists
9599
+ const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes);
9600
+ if (intrinsicAttributes !== unknownType) {
9601
+ paramType = intersectTypes(intrinsicAttributes, paramType);
9602
+ }
9603
+ return paramType;
9604
+ }
9605
+ }
9606
+ }
9607
+
9608
+ // Issue an error if this return type isn't assignable to JSX.ElementClass
9609
+ if (elemClassType) {
9610
+ checkTypeRelatedTo(elemInstanceType, elemClassType, assignableRelation, node, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
9611
+ }
9612
+
9613
+ if (isTypeAny(elemInstanceType)) {
9614
+ return elemInstanceType;
9615
+ }
9616
+
9617
+ const propsName = getJsxElementPropertiesName();
9618
+ if (propsName === undefined) {
9619
+ // There is no type ElementAttributesProperty, return 'any'
9620
+ return anyType;
9621
+ }
9622
+ else if (propsName === "") {
9623
+ // If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead
9624
+ return elemInstanceType;
9625
+ }
9626
+ else {
9627
+ const attributesType = getTypeOfPropertyOfType(elemInstanceType, propsName);
9628
+
9629
+ if (!attributesType) {
9630
+ // There is no property named 'props' on this instance type
9631
+ return emptyObjectType;
9632
+ }
9633
+ else if (isTypeAny(attributesType) || (attributesType === unknownType)) {
9634
+ // Props is of type 'any' or unknown
9635
+ return attributesType;
9636
+ }
9637
+ else if (attributesType.flags & TypeFlags.Union) {
9638
+ // Props cannot be a union type
9639
+ error(node.tagName, Diagnostics.JSX_element_attributes_type_0_may_not_be_a_union_type, typeToString(attributesType));
9640
+ return anyType;
9641
+ }
9642
+ else {
9643
+ // Normal case -- add in IntrinsicClassElements<T> and IntrinsicElements
9644
+ let apparentAttributesType = attributesType;
9645
+ const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes);
9646
+ if (intrinsicClassAttribs !== unknownType) {
9647
+ const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol);
9648
+ if (typeParams) {
9649
+ if (typeParams.length === 1) {
9650
+ apparentAttributesType = intersectTypes(createTypeReference(<GenericType>intrinsicClassAttribs, [elemInstanceType]), apparentAttributesType);
9651
+ }
9652
+ }
9653
+ else {
9654
+ apparentAttributesType = intersectTypes(attributesType, intrinsicClassAttribs);
9655
+ }
9656
+ }
9657
+
9658
+ const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes);
9659
+ if (intrinsicAttribs !== unknownType) {
9660
+ apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType);
9661
+ }
9662
+
9663
+ return apparentAttributesType;
9664
+ }
9665
+ }
9666
+ }
9667
+
9573
9668
/**
9574
9669
* Given an opening/self-closing element, get the 'element attributes type', i.e. the type that tells
9575
9670
* us which attributes are valid on a given element.
@@ -9585,96 +9680,15 @@ namespace ts {
9585
9680
else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) {
9586
9681
return links.resolvedJsxType = getIndexInfoOfSymbol(symbol, IndexKind.String).type;
9587
9682
}
9683
+ else {
9684
+ return links.resolvedJsxType = unknownType;
9685
+ }
9588
9686
}
9589
9687
else {
9590
- // Get the element instance type (the result of newing or invoking this tag)
9591
- const elemInstanceType = getJsxElementInstanceType(node);
9592
-
9593
9688
const elemClassType = getJsxGlobalElementClassType();
9594
-
9595
- if (!elemClassType || !isTypeAssignableTo(elemInstanceType, elemClassType)) {
9596
- // Is this is a stateless function component? See if its single signature's return type is
9597
- // assignable to the JSX Element Type
9598
- if (jsxElementType) {
9599
- const elemType = checkExpression(node.tagName);
9600
- const callSignatures = elemType && getSignaturesOfType(elemType, SignatureKind.Call);
9601
- const callSignature = callSignatures && callSignatures.length > 0 && callSignatures[0];
9602
- const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
9603
- let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0]));
9604
- if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType)) {
9605
- // Intersect in JSX.IntrinsicAttributes if it exists
9606
- const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes);
9607
- if (intrinsicAttributes !== unknownType) {
9608
- paramType = intersectTypes(intrinsicAttributes, paramType);
9609
- }
9610
- return links.resolvedJsxType = paramType;
9611
- }
9612
- }
9613
- }
9614
-
9615
- // Issue an error if this return type isn't assignable to JSX.ElementClass
9616
- if (elemClassType) {
9617
- checkTypeRelatedTo(elemInstanceType, elemClassType, assignableRelation, node, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
9618
- }
9619
-
9620
- if (isTypeAny(elemInstanceType)) {
9621
- return links.resolvedJsxType = elemInstanceType;
9622
- }
9623
-
9624
- const propsName = getJsxElementPropertiesName();
9625
- if (propsName === undefined) {
9626
- // There is no type ElementAttributesProperty, return 'any'
9627
- return links.resolvedJsxType = anyType;
9628
- }
9629
- else if (propsName === "") {
9630
- // If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead
9631
- return links.resolvedJsxType = elemInstanceType;
9632
- }
9633
- else {
9634
- const attributesType = getTypeOfPropertyOfType(elemInstanceType, propsName);
9635
-
9636
- if (!attributesType) {
9637
- // There is no property named 'props' on this instance type
9638
- return links.resolvedJsxType = emptyObjectType;
9639
- }
9640
- else if (isTypeAny(attributesType) || (attributesType === unknownType)) {
9641
- // Props is of type 'any' or unknown
9642
- return links.resolvedJsxType = attributesType;
9643
- }
9644
- else if (attributesType.flags & TypeFlags.Union) {
9645
- // Props cannot be a union type
9646
- error(node.tagName, Diagnostics.JSX_element_attributes_type_0_may_not_be_a_union_type, typeToString(attributesType));
9647
- return links.resolvedJsxType = anyType;
9648
- }
9649
- else {
9650
- // Normal case -- add in IntrinsicClassElements<T> and IntrinsicElements
9651
- let apparentAttributesType = attributesType;
9652
- const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes);
9653
- if (intrinsicClassAttribs !== unknownType) {
9654
- const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol);
9655
- if (typeParams) {
9656
- if (typeParams.length === 1) {
9657
- apparentAttributesType = intersectTypes(createTypeReference(<GenericType>intrinsicClassAttribs, [elemInstanceType]), apparentAttributesType);
9658
- }
9659
- }
9660
- else {
9661
- apparentAttributesType = intersectTypes(attributesType, intrinsicClassAttribs);
9662
- }
9663
- }
9664
-
9665
- const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes);
9666
- if (intrinsicAttribs !== unknownType) {
9667
- apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType);
9668
- }
9669
-
9670
- return links.resolvedJsxType = apparentAttributesType;
9671
- }
9672
- }
9689
+ return links.resolvedJsxType = getResolvedJsxType(node, undefined, elemClassType);
9673
9690
}
9674
-
9675
- return links.resolvedJsxType = unknownType;
9676
9691
}
9677
-
9678
9692
return links.resolvedJsxType;
9679
9693
}
9680
9694
0 commit comments