Skip to content

Commit e3b1487

Browse files
committed
Check all properties are present before checking types in relationships
1 parent 3ea031c commit e3b1487

File tree

1 file changed

+17
-18
lines changed

1 file changed

+17
-18
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9424,21 +9424,20 @@ namespace ts {
94249424
if (relation === identityRelation) {
94259425
return propertiesIdenticalTo(source, target);
94269426
}
9427+
const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral);
9428+
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties);
9429+
if (unmatchedProperty) {
9430+
if (reportErrors) {
9431+
reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(unmatchedProperty), typeToString(source));
9432+
}
9433+
return Ternary.False;
9434+
}
94279435
let result = Ternary.True;
94289436
const properties = getPropertiesOfObjectType(target);
9429-
const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral);
94309437
for (const targetProp of properties) {
9431-
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
9432-
if (sourceProp !== targetProp) {
9433-
if (!sourceProp) {
9434-
if (!(targetProp.flags & SymbolFlags.Optional) || requireOptionalProperties) {
9435-
if (reportErrors) {
9436-
reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(targetProp), typeToString(source));
9437-
}
9438-
return Ternary.False;
9439-
}
9440-
}
9441-
else if (!(targetProp.flags & SymbolFlags.Prototype)) {
9438+
if (!(targetProp.flags & SymbolFlags.Prototype)) {
9439+
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
9440+
if (sourceProp && sourceProp !== targetProp) {
94429441
const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp);
94439442
const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp);
94449443
if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) {
@@ -10463,17 +10462,17 @@ namespace ts {
1046310462
}
1046410463
}
1046510464

10466-
function isPossiblyAssignableTo(source: Type, target: Type) {
10465+
function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean) {
1046710466
const properties = getPropertiesOfObjectType(target);
1046810467
for (const targetProp of properties) {
10469-
if (!(targetProp.flags & (SymbolFlags.Optional | SymbolFlags.Prototype))) {
10470-
const sourceProp = getPropertyOfObjectType(source, targetProp.escapedName);
10468+
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) {
10469+
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
1047110470
if (!sourceProp) {
10472-
return false;
10471+
return targetProp;
1047310472
}
1047410473
}
1047510474
}
10476-
return true;
10475+
return undefined;
1047710476
}
1047810477

1047910478
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) {
@@ -10671,7 +10670,7 @@ namespace ts {
1067110670
}
1067210671
// Infer from the members of source and target only if the two types are possibly related. We check
1067310672
// in both directions because we may be inferring for a co-variant or a contra-variant position.
10674-
if (isPossiblyAssignableTo(source, target) || isPossiblyAssignableTo(target, source)) {
10673+
if (!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false) || !getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false)) {
1067510674
inferFromProperties(source, target);
1067610675
inferFromSignatures(source, target, SignatureKind.Call);
1067710676
inferFromSignatures(source, target, SignatureKind.Construct);

0 commit comments

Comments
 (0)