Skip to content

Commit 2c5117b

Browse files
author
Kanchalai Tanglertsampan
committed
Refactor "isKnownProperty" to be use outside of checkTypeScriptAssignable as JSX do excess property after
1 parent 788b2a3 commit 2c5117b

File tree

1 file changed

+21
-37
lines changed

1 file changed

+21
-37
lines changed

src/compiler/checker.ts

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8688,29 +8688,6 @@ namespace ts {
86888688
return Ternary.False;
86898689
}
86908690

8691-
// Check if a property with the given name is known anywhere in the given type. In an object type, a property
8692-
// is considered known if the object type is empty and the check is for assignability, if the object type has
8693-
// index signatures, or if the property is actually declared in the object type. In a union or intersection
8694-
// type, a property is considered known if it is known in any constituent type.
8695-
function isKnownProperty(type: Type, name: string, isComparingJsxAttributes: boolean): boolean {
8696-
if (type.flags & TypeFlags.Object) {
8697-
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
8698-
if (resolved.stringIndexInfo || resolved.numberIndexInfo && isNumericLiteralName(name) ||
8699-
getPropertyOfType(type, name) || isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) {
8700-
// For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known.
8701-
return true;
8702-
}
8703-
}
8704-
else if (type.flags & TypeFlags.UnionOrIntersection) {
8705-
for (const t of (<UnionOrIntersectionType>type).types) {
8706-
if (isKnownProperty(t, name, isComparingJsxAttributes)) {
8707-
return true;
8708-
}
8709-
}
8710-
}
8711-
return false;
8712-
}
8713-
87148691
function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean {
87158692
if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
87168693
const isComparingJsxAttributes = !!(source.flags & TypeFlags.JsxAttributes);
@@ -13875,21 +13852,26 @@ namespace ts {
1387513852
checkJsxAttributesAssignableToTagNameAttributes(node);
1387613853
}
1387713854

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);
13855+
/**
13856+
* Check if a property with the given name is known anywhere in the given type. In an object type, a property
13857+
* is considered known if the object type is empty and the check is for assignability, if the object type has
13858+
* index signatures, or if the property is actually declared in the object type. In a union or intersection
13859+
* type, a property is considered known if it is known in any constituent type.
13860+
* @param targetType a type to search a given name in
13861+
* @param name a property name to search
13862+
* @param isComparingJsxAttributes a boolean flag indicating whether we are searching in JsxAttributesType
13863+
*/
13864+
function isKnownProperty(targetType: Type, name: string, isComparingJsxAttributes: boolean): boolean {
13865+
if (targetType.flags & TypeFlags.Object) {
13866+
const resolved = resolveStructuredTypeMembers(<ObjectType>targetType);
1388513867
if (resolved.stringIndexInfo || resolved.numberIndexInfo && isNumericLiteralName(name) ||
13886-
getPropertyOfType(type, name) || isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) {
13868+
getPropertyOfType(targetType, name) || isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) {
1388713869
// For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known.
1388813870
return true;
1388913871
}
1389013872
}
13891-
else if (type.flags & TypeFlags.UnionOrIntersection) {
13892-
for (const t of (<UnionOrIntersectionType>type).types) {
13873+
else if (targetType.flags & TypeFlags.UnionOrIntersection) {
13874+
for (const t of (<UnionOrIntersectionType>targetType).types) {
1389313875
if (isKnownProperty(t, name, isComparingJsxAttributes)) {
1389413876
return true;
1389513877
}
@@ -13898,7 +13880,7 @@ namespace ts {
1389813880
return false;
1389913881
}
1390013882

13901-
/**
13883+
/**
1390213884
* Check whether the given attributes of JSX opening-like element is assignable to the tagName attributes.
1390313885
* Get the attributes type of the opening-like element through resolving the tagName, "target attributes"
1390413886
* Check assignablity between given attributes property, "source attributes", and the "target attributes"
@@ -13930,14 +13912,16 @@ namespace ts {
1393013912
error(openingLikeElement, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, getJsxElementPropertiesName());
1393113913
}
1393213914
else {
13915+
// Check if sourceAttributesType assignable to targetAttributesType though this check will allow excess properties
1393313916
const isSourceAttributeTypeAssignableToTarget = checkTypeAssignableTo(sourceAttributesType, targetAttributesType, openingLikeElement.attributes.properties.length > 0 ? openingLikeElement.attributes : openingLikeElement);
13934-
// After we check for assignability, we will do another pass to check that
13935-
// all explicitly specified attributes have correct name corresponding with target (as those will be assignable as spread type allows excess properties)
13936-
// Note: if the type of these explicitly specified attributes do not match it will be an error during above assignability check.
13917+
// After we check for assignability, we will do another pass to check that all explicitly specified attributes have correct name corresponding in targetAttributeType.
13918+
// This will allow excess properties in spread type as it is very common pattern to spread outter attributes into React component in its render method.
1393713919
if (isSourceAttributeTypeAssignableToTarget && !isTypeAny(sourceAttributesType) && !isTypeAny(targetAttributesType)) {
1393813920
for (const attribute of openingLikeElement.attributes.properties) {
1393913921
if (isJsxAttribute(attribute) && !isKnownProperty(targetAttributesType, attribute.name.text, /*isComparingJsxAttributes*/ true)) {
1394013922
error(attribute, Diagnostics.Property_0_does_not_exist_on_type_1, attribute.name.text, typeToString(targetAttributesType));
13923+
// We break here so that errors won't be cascading
13924+
break;
1394113925
}
1394213926
}
1394313927
}

0 commit comments

Comments
 (0)