@@ -11398,7 +11398,7 @@ namespace ts {
11398
11398
// When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type
11399
11399
// which is a type of the parameter of the signature we are trying out.
11400
11400
// If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName
11401
- const attributesType = getContextualType(<Expression>attribute.parent) || getAttributesTypeFromJsxOpeningLikeElement(<JsxOpeningLikeElement>attribute.parent.parent) ;
11401
+ const attributesType = getContextualType(<Expression>attribute.parent);
11402
11402
11403
11403
if (isJsxAttribute(attribute)) {
11404
11404
if (!attributesType || isTypeAny(attributesType)) {
@@ -12071,42 +12071,6 @@ namespace ts {
12071
12071
return createJsxAttributesTypeFromAttributesProperty(node.parent as JsxOpeningLikeElement, /*filter*/ undefined, contextualMapper);
12072
12072
}
12073
12073
12074
- /**
12075
- * Check whether the given attributes of JSX opening-like element is assignable to the tagName attributes.
12076
- * Get the attributes type of the opening-like element through resolving the tagName, "target attributes"
12077
- * Check assignablity between given attributes property, "source attributes", and the "target attributes"
12078
- * @param openingLikeElement an opening-like JSX element to check its JSXAttributes
12079
- */
12080
- function checkJsxAttributesAssignableToTagNameAttributes(openingLikeElement: JsxOpeningLikeElement) {
12081
- // The function involves following steps:
12082
- // 1. Figure out expected attributes type by resolving tagName of the JSX opening-like element, targetAttributesType.
12083
- // During these steps, we will try to resolve the tagName as intrinsic name, stateless function, stateful component (in the order)
12084
- // 2. Solved JSX attributes type given by users, sourceAttributesType, which is by resolving "attributes" property of the JSX opening-like element.
12085
- // 3. Check if the two are assignable to each other
12086
-
12087
- // targetAttributesType is a type of an attributes from resolving tagName of an opening-like JSX element.
12088
- const targetAttributesType = isJsxIntrinsicIdentifier(openingLikeElement.tagName) ?
12089
- getIntrinsicAttributesTypeFromJsxOpeningLikeElement(openingLikeElement) :
12090
- getCustomJsxElementAttributesType(openingLikeElement, /*shouldIncludeAllStatelessAttributesType*/ false);
12091
-
12092
- // sourceAttributesType is a type of an attributes properties.
12093
- // i.e <div attr1={10} attr2="string" />
12094
- // attr1 and attr2 are treated as JSXAttributes attached in the JsxOpeningLikeElement as "attributes".
12095
- const sourceAttributesType = createJsxAttributesTypeFromAttributesProperty(openingLikeElement,
12096
- attribute => {
12097
- return isUnhyphenatedJsxName(attribute.name) || !!(getPropertyOfType(targetAttributesType, attribute.name));
12098
- });
12099
-
12100
- // If the targetAttributesType is an emptyObjectType, indicating that there is no property named 'props' on this instance type.
12101
- // but there exists a sourceAttributesType, we need to explicitly give an error as normal assignability check allow excess properties and will pass.
12102
- if (targetAttributesType === emptyObjectType && (isTypeAny(sourceAttributesType) || (<ResolvedType>sourceAttributesType).properties.length > 0)) {
12103
- error(openingLikeElement, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, getJsxElementPropertiesName());
12104
- }
12105
- else {
12106
- checkTypeAssignableTo(sourceAttributesType, targetAttributesType, openingLikeElement.attributes.properties.length > 0 ? openingLikeElement.attributes : openingLikeElement);
12107
- }
12108
- }
12109
-
12110
12074
function getJsxType(name: string) {
12111
12075
let jsxType = jsxTypes.get(name);
12112
12076
if (jsxType === undefined) {
@@ -12462,6 +12426,7 @@ namespace ts {
12462
12426
* Get attributes type of the given custom opening-like JSX element.
12463
12427
* This function is intended to be called from a caller that handles intrinsic JSX element already.
12464
12428
* @param node a custom JSX opening-like element
12429
+ * @param shouldIncludeAllStatelessAttributesType a boolean value used by language service to get all possible attributes type from an overload stateless function component
12465
12430
*/
12466
12431
function getCustomJsxElementAttributesType(node: JsxOpeningLikeElement, shouldIncludeAllStatelessAttributesType: boolean): Type {
12467
12432
const links = getNodeLinks(node);
@@ -12489,7 +12454,7 @@ namespace ts {
12489
12454
}
12490
12455
12491
12456
/**
12492
- * Get the attributes type which is the type that indicate which attributes are valid on the given JSXOpeningLikeElement.
12457
+ * Get the attributes type, which indicates the attributes that are valid on the given JSXOpeningLikeElement.
12493
12458
* @param node a JSXOpeningLikeElement node
12494
12459
* @return an attributes type of the given node
12495
12460
*/
@@ -12520,7 +12485,9 @@ namespace ts {
12520
12485
return jsxElementClassType;
12521
12486
}
12522
12487
12523
- // Returns all the properties of the Jsx.IntrinsicElements interface
12488
+ /**
12489
+ * Returns all the properties of the Jsx.IntrinsicElements interface
12490
+ */
12524
12491
function getJsxIntrinsicTagNames(): Symbol[] {
12525
12492
const intrinsics = getJsxType(JsxNames.IntrinsicElements);
12526
12493
return intrinsics ? getPropertiesOfType(intrinsics) : emptyArray;
@@ -12561,6 +12528,42 @@ namespace ts {
12561
12528
checkJsxAttributesAssignableToTagNameAttributes(node);
12562
12529
}
12563
12530
12531
+ /**
12532
+ * Check whether the given attributes of JSX opening-like element is assignable to the tagName attributes.
12533
+ * Get the attributes type of the opening-like element through resolving the tagName, "target attributes"
12534
+ * Check assignablity between given attributes property, "source attributes", and the "target attributes"
12535
+ * @param openingLikeElement an opening-like JSX element to check its JSXAttributes
12536
+ */
12537
+ function checkJsxAttributesAssignableToTagNameAttributes(openingLikeElement: JsxOpeningLikeElement) {
12538
+ // The function involves following steps:
12539
+ // 1. Figure out expected attributes type by resolving tagName of the JSX opening-like element, targetAttributesType.
12540
+ // During these steps, we will try to resolve the tagName as intrinsic name, stateless function, stateful component (in the order)
12541
+ // 2. Solved JSX attributes type given by users, sourceAttributesType, which is by resolving "attributes" property of the JSX opening-like element.
12542
+ // 3. Check if the two are assignable to each other
12543
+
12544
+ // targetAttributesType is a type of an attributes from resolving tagName of an opening-like JSX element.
12545
+ const targetAttributesType = isJsxIntrinsicIdentifier(openingLikeElement.tagName) ?
12546
+ getIntrinsicAttributesTypeFromJsxOpeningLikeElement(openingLikeElement) :
12547
+ getCustomJsxElementAttributesType(openingLikeElement, /*shouldIncludeAllStatelessAttributesType*/ false);
12548
+
12549
+ // sourceAttributesType is a type of an attributes properties.
12550
+ // i.e <div attr1={10} attr2="string" />
12551
+ // attr1 and attr2 are treated as JSXAttributes attached in the JsxOpeningLikeElement as "attributes".
12552
+ const sourceAttributesType = createJsxAttributesTypeFromAttributesProperty(openingLikeElement,
12553
+ attribute => {
12554
+ return isUnhyphenatedJsxName(attribute.name) || !!(getPropertyOfType(targetAttributesType, attribute.name));
12555
+ });
12556
+
12557
+ // If the targetAttributesType is an emptyObjectType, indicating that there is no property named 'props' on this instance type.
12558
+ // but there exists a sourceAttributesType, we need to explicitly give an error as normal assignability check allow excess properties and will pass.
12559
+ if (targetAttributesType === emptyObjectType && (isTypeAny(sourceAttributesType) || (<ResolvedType>sourceAttributesType).properties.length > 0)) {
12560
+ error(openingLikeElement, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, getJsxElementPropertiesName());
12561
+ }
12562
+ else {
12563
+ checkTypeAssignableTo(sourceAttributesType, targetAttributesType, openingLikeElement.attributes.properties.length > 0 ? openingLikeElement.attributes : openingLikeElement);
12564
+ }
12565
+ }
12566
+
12564
12567
function checkJsxExpression(node: JsxExpression, contextualMapper?: TypeMapper) {
12565
12568
if (node.expression) {
12566
12569
const type = checkExpression(node.expression, contextualMapper);
@@ -13021,9 +13024,7 @@ namespace ts {
13021
13024
let spreadArgIndex = -1;
13022
13025
13023
13026
if (isJsxOpeningLikeElement(node)) {
13024
- // For JSX opening-like element, we will ignore regular arity check (which is what is done here).
13025
- // Instead, the arity check will be done in "checkApplicableSignatureForJsxOpeningLikeElement" as we are required to figure out
13026
- // all property inside the given attributes.
13027
+ // The arity check will be done in "checkApplicableSignatureForJsxOpeningLikeElement".
13027
13028
return true;
13028
13029
}
13029
13030
@@ -13250,14 +13251,14 @@ namespace ts {
13250
13251
// However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props,
13251
13252
// can be specified by users through attributes property.
13252
13253
const paramType = getTypeAtPosition(signature, 0);
13253
- const argType = checkExpressionWithContextualType(node.attributes, paramType, /*contextualMapper*/ undefined);
13254
- const argProperties = getPropertiesOfType(argType );
13254
+ const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*contextualMapper*/ undefined);
13255
+ const argProperties = getPropertiesOfType(attributesType );
13255
13256
for (const arg of argProperties) {
13256
13257
if (!getPropertyOfType(paramType, arg.name) && isUnhyphenatedJsxName(arg.name)) {
13257
13258
return false;
13258
13259
}
13259
13260
}
13260
- if (checkTypeRelatedTo(argType , paramType, relation, /*errorNode*/ undefined, headMessage)) {
13261
+ if (checkTypeRelatedTo(attributesType , paramType, relation, /*errorNode*/ undefined, headMessage)) {
13261
13262
return true;
13262
13263
}
13263
13264
return false;
@@ -13744,16 +13745,15 @@ namespace ts {
13744
13745
// If candidate is undefined, it means that no candidates had a suitable arity. In that case,
13745
13746
// skip the checkApplicableSignature check.
13746
13747
if (candidateForArgumentError) {
13748
+ if (isJsxOpeningOrSelfClosingElement) {
13749
+ // We do not report any error here because any error will be handled in "resolveCustomJsxElementAttributesType".
13750
+ return candidateForArgumentError;
13751
+ }
13747
13752
// excludeArgument is undefined, in this case also equivalent to [undefined, undefined, ...]
13748
13753
// The importance of excludeArgument is to prevent us from typing function expression parameters
13749
13754
// in arguments too early. If possible, we'd like to only type them once we know the correct
13750
13755
// overload. However, this matters for the case where the call is correct. When the call is
13751
13756
// an error, we don't need to exclude any arguments, although it would cause no harm to do so.
13752
- if (isJsxOpeningOrSelfClosingElement) {
13753
- // If there is not result, just return the last one we try as a candidate.
13754
- // We do not report any error here because any error will be handled in "resolveCustomJsxElementAttributesType".
13755
- return candidateForArgumentError;
13756
- }
13757
13757
checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true);
13758
13758
}
13759
13759
else if (candidateForTypeArgumentError) {
0 commit comments