@@ -411,6 +411,9 @@ namespace ts {
411411
412412 let _jsxNamespace: string;
413413 let _jsxFactoryEntity: EntityName;
414+ let _jsxElementAttribPropInterfaceSymbol: Symbol; // JSX.ElementAttributesProperty [symbol]
415+ let _jsxElementPropertiesName: string;
416+ let _jsxElementChildrenPropertyName: string;
414417
415418 /** Things we lazy load from the JSX namespace */
416419 const jsxTypes = createMap<Type>();
@@ -424,8 +427,6 @@ namespace ts {
424427 IntrinsicClassAttributes: "IntrinsicClassAttributes"
425428 };
426429
427- const jsxChildrenPropertyName = "children";
428-
429430 const subtypeRelation = createMap<RelationComparisonResult>();
430431 const assignableRelation = createMap<RelationComparisonResult>();
431432 const comparableRelation = createMap<RelationComparisonResult>();
@@ -458,7 +459,7 @@ namespace ts {
458459 return checker;
459460
460461 function getJsxNamespace(): string {
461- if (_jsxNamespace === undefined ) {
462+ if (! _jsxNamespace) {
462463 _jsxNamespace = "React";
463464 if (compilerOptions.jsxFactory) {
464465 _jsxFactoryEntity = parseIsolatedEntityName(compilerOptions.jsxFactory, languageVersion);
@@ -12652,8 +12653,9 @@ namespace ts {
1265212653 return getTypeOfPropertyOfType(attributesType, (node.parent as JsxAttribute).name.text);
1265312654 }
1265412655 else if (node.parent.kind === SyntaxKind.JsxElement) {
12655- // JSX expression is in children of JSX Element, we will look for an atttribute named "chidlren"
12656- return getTypeOfPropertyOfType(attributesType, jsxChildrenPropertyName);
12656+ // JSX expression is in children of JSX Element, we will look for an "children" atttribute (we get the name from JSX.ElementAttributesProperty)
12657+ const jsxChildrenPropertyName = getJsxElementChildrenPropertyname();
12658+ return jsxChildrenPropertyName ? getTypeOfPropertyOfType(attributesType, jsxChildrenPropertyName) : anyType;
1265712659 }
1265812660 else {
1265912661 // JSX expression is in JSX spread attribute
@@ -13298,18 +13300,9 @@ namespace ts {
1329813300 }
1329913301
1330013302 // Handle children attribute
13301- const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ?
13302- openingLikeElement.parent as JsxElement : undefined;
13303+ const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ? openingLikeElement.parent as JsxElement : undefined;
1330313304 // We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement
1330413305 if (parent && parent.openingElement === openingLikeElement && parent.children.length > 0) {
13305- // Error if there is a attribute named "children" and children element.
13306- // This is because children element will overwrite the value from attributes
13307- if (attributesTable.has(jsxChildrenPropertyName)) {
13308- error(attributes, Diagnostics.props_children_are_specified_twice_The_attribute_named_children_will_be_overwritten);
13309- }
13310-
13311- // If there are children in the body of JSX element, create dummy attribute "children" with anyType so that it will pass the attribute checking process
13312- const childrenPropSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, jsxChildrenPropertyName);
1331313306 const childrenTypes: Type[] = [];
1331413307 for (const child of (parent as JsxElement).children) {
1331513308 // In React, JSX text that contains only whitespaces will be ignored so we don't want to type-check that
@@ -13323,11 +13316,22 @@ namespace ts {
1332313316 childrenTypes.push(checkExpression(child, checkMode));
1332413317 }
1332513318 }
13326- childrenPropSymbol.type = childrenTypes.length === 1 ?
13327- childrenTypes[0] :
13328- createArrayType(getUnionType(childrenTypes, /*subtypeReduction*/ false));
13329- attributesTable.set(jsxChildrenPropertyName, childrenPropSymbol);
13330- containsSynthesizedJsxChildren = true;
13319+
13320+ // Error if there is a attribute named "children" and children element.
13321+ // This is because children element will overwrite the value from attributes
13322+ const jsxChildrenPropertyName = getJsxElementChildrenPropertyname();
13323+ if (jsxChildrenPropertyName) {
13324+ if (attributesTable.has(jsxChildrenPropertyName)) {
13325+ error(attributes, Diagnostics.props_children_are_specified_twice_The_attribute_named_children_will_be_overwritten);
13326+ }
13327+
13328+ // If there are children in the body of JSX element, create dummy attribute "children" with anyType so that it will pass the attribute checking process
13329+ const childrenPropSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, jsxChildrenPropertyName);
13330+ childrenPropSymbol.type = childrenTypes.length === 1 ?
13331+ childrenTypes[0] :
13332+ createArrayType(getUnionType(childrenTypes, /*subtypeReduction*/ false));
13333+ attributesTable.set(jsxChildrenPropertyName, childrenPropSymbol);
13334+ }
1333113335 }
1333213336
1333313337 return createJsxAttributesType(attributes.symbol, attributesTable);
@@ -13429,41 +13433,85 @@ namespace ts {
1342913433 return getUnionType(map(signatures, getReturnTypeOfSignature), /*subtypeReduction*/ true);
1343013434 }
1343113435
13436+ function getPropertiesFromJsxElementAttributesProperty() {
13437+ if (!_jsxElementAttribPropInterfaceSymbol) {
13438+ // JSX
13439+ const jsxNamespace = getGlobalSymbol(JsxNames.JSX, SymbolFlags.Namespace, /*diagnosticMessage*/undefined);
13440+ // JSX.ElementAttributesProperty [symbol]
13441+ _jsxElementAttribPropInterfaceSymbol = jsxNamespace && getSymbol(jsxNamespace.exports, JsxNames.ElementAttributesPropertyNameContainer, SymbolFlags.Type);
13442+ }
13443+ return _jsxElementAttribPropInterfaceSymbol;
13444+ }
13445+
1343213446 /// e.g. "props" for React.d.ts,
1343313447 /// or 'undefined' if ElementAttributesProperty doesn't exist (which means all
1343413448 /// non-intrinsic elements' attributes type is 'any'),
1343513449 /// or '' if it has 0 properties (which means every
1343613450 /// non-intrinsic elements' attributes type is the element instance type)
1343713451 function getJsxElementPropertiesName() {
13438- // JSX
13439- const jsxNamespace = getGlobalSymbol(JsxNames.JSX, SymbolFlags.Namespace, /*diagnosticMessage*/undefined);
13440- // JSX.ElementAttributesProperty [symbol]
13441- const attribsPropTypeSym = jsxNamespace && getSymbol(jsxNamespace.exports, JsxNames.ElementAttributesPropertyNameContainer, SymbolFlags.Type);
13442- // JSX.ElementAttributesProperty [type]
13443- const attribPropType = attribsPropTypeSym && getDeclaredTypeOfSymbol(attribsPropTypeSym);
13444- // The properties of JSX.ElementAttributesProperty
13445- const attribProperties = attribPropType && getPropertiesOfType(attribPropType);
13446-
13447- if (attribProperties) {
13448- // Element Attributes has zero properties, so the element attributes type will be the class instance type
13449- if (attribProperties.length === 0) {
13450- return "";
13451- }
13452- // Element Attributes has one property, so the element attributes type will be the type of the corresponding
13453- // property of the class instance type
13454- else if (attribProperties.length === 1) {
13455- return attribProperties[0].name;
13456- }
13457- // More than one property on ElementAttributesProperty is an error
13452+ if (!_jsxElementPropertiesName) {
13453+ const jsxElementAttribPropInterfaceSym = getPropertiesFromJsxElementAttributesProperty();
13454+ // JSX.ElementAttributesProperty [type]
13455+ const jsxElementAttribPropInterfaceType = jsxElementAttribPropInterfaceSym && getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym);
13456+ // The properties of JSX.ElementAttributesProperty
13457+ const propertiesOfJsxElementAttribPropInterface = jsxElementAttribPropInterfaceType && getPropertiesOfType(jsxElementAttribPropInterfaceType);
13458+
13459+ // if there is a property in JSX.ElementAttributesProperty
13460+ // i.e.
13461+ // interface ElementAttributesProperty {
13462+ // props: {
13463+ // children?: any;
13464+ // };
13465+ // }
13466+ if (propertiesOfJsxElementAttribPropInterface) {
13467+ // Element Attributes has zero properties, so the element attributes type will be the class instance type
13468+ if (propertiesOfJsxElementAttribPropInterface.length === 0) {
13469+ _jsxElementPropertiesName = "";
13470+ }
13471+ // Element Attributes has one property, so the element attributes type will be the type of the corresponding
13472+ // property of the class instance type
13473+ else if (propertiesOfJsxElementAttribPropInterface.length === 1) {
13474+ _jsxElementPropertiesName = propertiesOfJsxElementAttribPropInterface[0].name;
13475+ }
13476+ // More than one property on ElementAttributesProperty is an error
13477+ else {
13478+ error(jsxElementAttribPropInterfaceSym.declarations[0], Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, JsxNames.ElementAttributesPropertyNameContainer);
13479+ _jsxElementPropertiesName = undefined;
13480+ }
13481+ }
1345813482 else {
13459- error(attribsPropTypeSym.declarations[0], Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, JsxNames.ElementAttributesPropertyNameContainer);
13460- return undefined;
13483+ // No interface exists, so the element attributes type will be an implicit any
13484+ _jsxElementPropertiesName = undefined;
1346113485 }
1346213486 }
13463- else {
13464- // No interface exists, so the element attributes type will be an implicit any
13465- return undefined;
13487+
13488+ return _jsxElementPropertiesName;
13489+ }
13490+
13491+ function getJsxElementChildrenPropertyname(): string {
13492+ if (!_jsxElementChildrenPropertyName) {
13493+ const jsxElementAttribPropInterfaceSym = getPropertiesFromJsxElementAttributesProperty();
13494+ // JSX.ElementAttributesProperty [type]
13495+ const jsxElementAttribPropInterfaceType = jsxElementAttribPropInterfaceSym && getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym);
13496+ // The properties of JSX.ElementAttributesProperty
13497+ const propertiesOfJsxElementAttribPropInterface = jsxElementAttribPropInterfaceType && getPropertiesOfType(jsxElementAttribPropInterfaceType);
13498+ // if there is a property in JSX.ElementAttributesProperty
13499+ // i.e.
13500+ // interface ElementAttributesProperty {
13501+ // props: {
13502+ // children?: any;
13503+ // };
13504+ // }
13505+ if (propertiesOfJsxElementAttribPropInterface && propertiesOfJsxElementAttribPropInterface.length === 1) {
13506+ const propsType = getTypeOfSymbol(propertiesOfJsxElementAttribPropInterface[0]);
13507+ const propertiesOfProps = propsType && getPropertiesOfType(propsType);
13508+ if (propertiesOfProps && propertiesOfProps.length === 1) {
13509+ _jsxElementChildrenPropertyName = propertiesOfProps[0].name;
13510+ }
13511+ }
1346613512 }
13513+
13514+ return _jsxElementChildrenPropertyName;
1346713515 }
1346813516
1346913517 /**
0 commit comments