@@ -13356,9 +13356,7 @@ namespace ts {
13356
13356
*/
13357
13357
function createJsxAttributesType(symbol: Symbol, attributesTable: Map<Symbol>) {
13358
13358
const result = createAnonymousType(symbol, attributesTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
13359
- // 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.
13360
- const freshObjectLiteralFlag = spread !== emptyObjectType || compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
13361
- result.flags |= TypeFlags.JsxAttributes | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag;
13359
+ result.flags |= TypeFlags.JsxAttributes | TypeFlags.ContainsObjectLiteral;
13362
13360
result.objectFlags |= ObjectFlags.ObjectLiteral;
13363
13361
return result;
13364
13362
}
@@ -13877,7 +13875,30 @@ namespace ts {
13877
13875
checkJsxAttributesAssignableToTagNameAttributes(node);
13878
13876
}
13879
13877
13880
- /**
13878
+ // Check if a property with the given name is known anywhere in the given type. In an object type, a property
13879
+ // is considered known if the object type is empty and the check is for assignability, if the object type has
13880
+ // index signatures, or if the property is actually declared in the object type. In a union or intersection
13881
+ // type, a property is considered known if it is known in any constituent type.
13882
+ function isKnownProperty(type: Type, name: string, isComparingJsxAttributes: boolean): boolean {
13883
+ if (type.flags & TypeFlags.Object) {
13884
+ const resolved = resolveStructuredTypeMembers(<ObjectType>type);
13885
+ if (resolved.stringIndexInfo || resolved.numberIndexInfo && isNumericLiteralName(name) ||
13886
+ getPropertyOfType(type, name) || isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) {
13887
+ // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known.
13888
+ return true;
13889
+ }
13890
+ }
13891
+ else if (type.flags & TypeFlags.UnionOrIntersection) {
13892
+ for (const t of (<UnionOrIntersectionType>type).types) {
13893
+ if (isKnownProperty(t, name, isComparingJsxAttributes)) {
13894
+ return true;
13895
+ }
13896
+ }
13897
+ }
13898
+ return false;
13899
+ }
13900
+
13901
+ /**
13881
13902
* Check whether the given attributes of JSX opening-like element is assignable to the tagName attributes.
13882
13903
* Get the attributes type of the opening-like element through resolving the tagName, "target attributes"
13883
13904
* Check assignablity between given attributes property, "source attributes", and the "target attributes"
@@ -13910,12 +13931,12 @@ namespace ts {
13910
13931
}
13911
13932
else {
13912
13933
const isSourceAttributeTypeAssignableToTarget = checkTypeAssignableTo(sourceAttributesType, targetAttributesType, openingLikeElement.attributes.properties.length > 0 ? openingLikeElement.attributes : openingLikeElement);
13913
- // 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
13934
+ // After we check for assignability, we will do another pass to check that
13914
13935
// all explicitly specified attributes have correct name corresponding with target (as those will be assignable as spread type allows excess properties)
13915
13936
// Note: if the type of these explicitly specified attributes do not match it will be an error during above assignability check.
13916
- if (isSourceAttributeTypeAssignableToTarget && sourceAttributesType !== anyType && !(sourceAttributesType.flags & TypeFlags.FreshLiteral )) {
13937
+ if (isSourceAttributeTypeAssignableToTarget && !isTypeAny( sourceAttributesType) && !isTypeAny(targetAttributesType )) {
13917
13938
for (const attribute of openingLikeElement.attributes.properties) {
13918
- if (isJsxAttribute(attribute) && !getPropertyOfType (targetAttributesType, attribute.name.text)) {
13939
+ if (isJsxAttribute(attribute) && !isKnownProperty (targetAttributesType, attribute.name.text, /*isComparingJsxAttributes*/ true )) {
13919
13940
error(attribute, Diagnostics.Property_0_does_not_exist_on_type_1, attribute.name.text, typeToString(targetAttributesType));
13920
13941
}
13921
13942
}
0 commit comments