@@ -13319,9 +13319,7 @@ namespace ts {
13319
13319
*/
13320
13320
function createJsxAttributesType(symbol: Symbol, attributesTable: Map<Symbol>) {
13321
13321
const result = createAnonymousType(symbol, attributesTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
13322
- // Spread object doesn't have freshness flag to allow excess attributes as it is very common for parent component to spread its "props" to other components in its render method.
13323
- const freshObjectLiteralFlag = spread !== emptyObjectType || compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
13324
- result.flags |= TypeFlags.JsxAttributes | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag;
13322
+ result.flags |= TypeFlags.JsxAttributes | TypeFlags.ContainsObjectLiteral;
13325
13323
result.objectFlags |= ObjectFlags.ObjectLiteral;
13326
13324
return result;
13327
13325
}
@@ -13840,7 +13838,30 @@ namespace ts {
13840
13838
checkJsxAttributesAssignableToTagNameAttributes(node);
13841
13839
}
13842
13840
13843
- /**
13841
+ // Check if a property with the given name is known anywhere in the given type. In an object type, a property
13842
+ // is considered known if the object type is empty and the check is for assignability, if the object type has
13843
+ // index signatures, or if the property is actually declared in the object type. In a union or intersection
13844
+ // type, a property is considered known if it is known in any constituent type.
13845
+ function isKnownProperty(type: Type, name: string, isComparingJsxAttributes: boolean): boolean {
13846
+ if (type.flags & TypeFlags.Object) {
13847
+ const resolved = resolveStructuredTypeMembers(<ObjectType>type);
13848
+ if (resolved.stringIndexInfo || resolved.numberIndexInfo && isNumericLiteralName(name) ||
13849
+ getPropertyOfType(type, name) || isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) {
13850
+ // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known.
13851
+ return true;
13852
+ }
13853
+ }
13854
+ else if (type.flags & TypeFlags.UnionOrIntersection) {
13855
+ for (const t of (<UnionOrIntersectionType>type).types) {
13856
+ if (isKnownProperty(t, name, isComparingJsxAttributes)) {
13857
+ return true;
13858
+ }
13859
+ }
13860
+ }
13861
+ return false;
13862
+ }
13863
+
13864
+ /**
13844
13865
* Check whether the given attributes of JSX opening-like element is assignable to the tagName attributes.
13845
13866
* Get the attributes type of the opening-like element through resolving the tagName, "target attributes"
13846
13867
* Check assignablity between given attributes property, "source attributes", and the "target attributes"
@@ -13873,12 +13894,12 @@ namespace ts {
13873
13894
}
13874
13895
else {
13875
13896
const isSourceAttributeTypeAssignableToTarget = checkTypeAssignableTo(sourceAttributesType, targetAttributesType, openingLikeElement.attributes.properties.length > 0 ? openingLikeElement.attributes : openingLikeElement);
13876
- // If sourceAttributesType has spread (e.g the type doesn't have freshness flag) after we check for assignability, we will do another pass to check that
13897
+ // After we check for assignability, we will do another pass to check that
13877
13898
// all explicitly specified attributes have correct name corresponding with target (as those will be assignable as spread type allows excess properties)
13878
13899
// Note: if the type of these explicitly specified attributes do not match it will be an error during above assignability check.
13879
- if (isSourceAttributeTypeAssignableToTarget && sourceAttributesType !== anyType && !(sourceAttributesType.flags & TypeFlags.FreshLiteral )) {
13900
+ if (isSourceAttributeTypeAssignableToTarget && !isTypeAny( sourceAttributesType) && !isTypeAny(targetAttributesType )) {
13880
13901
for (const attribute of openingLikeElement.attributes.properties) {
13881
- if (isJsxAttribute(attribute) && !getPropertyOfType (targetAttributesType, attribute.name.text)) {
13902
+ if (isJsxAttribute(attribute) && !isKnownProperty (targetAttributesType, attribute.name.text, /*isComparingJsxAttributes*/ true )) {
13882
13903
error(attribute, Diagnostics.Property_0_does_not_exist_on_type_1, attribute.name.text, typeToString(targetAttributesType));
13883
13904
}
13884
13905
}
0 commit comments