Skip to content

Commit 1d2df84

Browse files
committed
Improve excess property checking logic
1 parent 03a98a2 commit 1d2df84

File tree

1 file changed

+16
-10
lines changed

1 file changed

+16
-10
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11836,7 +11836,7 @@ namespace ts {
1183611836
if (!noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral) {
1183711837
return false; // Disable excess property checks on JS literals to simulate having an implicit "index signature" - but only outside of noImplicitAny
1183811838
}
11839-
if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
11839+
if (isExcessPropertyCheckTarget(target)) {
1184011840
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
1184111841
if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
1184211842
(isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) {
@@ -11849,6 +11849,9 @@ namespace ts {
1184911849
for (const prop of getPropertiesOfObjectType(source)) {
1185011850
if (shouldCheckAsExcessProperty(prop, source.symbol) && !isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) {
1185111851
if (reportErrors) {
11852+
// Report error in terms of object types in the target as those are the only ones
11853+
// we check in isKnownProperty.
11854+
const errorTarget = filterType(target, isExcessPropertyCheckTarget);
1185211855
// We know *exactly* where things went wrong when comparing the types.
1185311856
// Use this property as the error node as this will be more helpful in
1185411857
// reasoning about what went wrong.
@@ -11857,7 +11860,7 @@ namespace ts {
1185711860
// JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal.
1185811861
// However, using an object-literal error message will be very confusing to the users so we give different a message.
1185911862
// TODO: Spelling suggestions for excess jsx attributes (needs new diagnostic messages)
11860-
reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(target));
11863+
reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(errorTarget));
1186111864
}
1186211865
else {
1186311866
// use the property's value declaration if the property is assigned inside the literal itself
@@ -11871,17 +11874,17 @@ namespace ts {
1187111874

1187211875
const name = propDeclaration.name!;
1187311876
if (isIdentifier(name)) {
11874-
suggestion = getSuggestionForNonexistentProperty(name, target);
11877+
suggestion = getSuggestionForNonexistentProperty(name, errorTarget);
1187511878
}
1187611879
}
1187711880

1187811881
if (suggestion !== undefined) {
1187911882
reportError(Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2,
11880-
symbolToString(prop), typeToString(target), suggestion);
11883+
symbolToString(prop), typeToString(errorTarget), suggestion);
1188111884
}
1188211885
else {
1188311886
reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1,
11884-
symbolToString(prop), typeToString(target));
11887+
symbolToString(prop), typeToString(errorTarget));
1188511888
}
1188611889
}
1188711890
}
@@ -18595,20 +18598,23 @@ namespace ts {
1859518598
return true;
1859618599
}
1859718600
}
18598-
else if (targetType.flags & TypeFlags.UnionOrIntersection) {
18601+
else if (targetType.flags & TypeFlags.UnionOrIntersection && isExcessPropertyCheckTarget(targetType)) {
1859918602
for (const t of (targetType as UnionOrIntersectionType).types) {
1860018603
if (isKnownProperty(t, name, isComparingJsxAttributes)) {
1860118604
return true;
1860218605
}
1860318606
}
1860418607
}
18605-
else if (targetType.flags & TypeFlags.Conditional) {
18606-
return isKnownProperty((targetType as ConditionalType).root.trueType, name, isComparingJsxAttributes) ||
18607-
isKnownProperty((targetType as ConditionalType).root.falseType, name, isComparingJsxAttributes);
18608-
}
1860918608
return false;
1861018609
}
1861118610

18611+
function isExcessPropertyCheckTarget(type: Type): boolean {
18612+
return !!(type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) ||
18613+
type.flags & TypeFlags.NonPrimitive ||
18614+
type.flags & TypeFlags.Union && some((<UnionType>type).types, isExcessPropertyCheckTarget) ||
18615+
type.flags & TypeFlags.Intersection && every((<IntersectionType>type).types, isExcessPropertyCheckTarget));
18616+
}
18617+
1861218618
function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) {
1861318619
if (node.expression) {
1861418620
const type = checkExpression(node.expression, checkMode);

0 commit comments

Comments
 (0)