Check all properties are present before checking types in relationships

This commit is contained in:
Anders Hejlsberg 2017-08-29 09:00:17 -07:00
parent 3ea031cf1c
commit e3b1487240

View file

@ -9424,21 +9424,20 @@ namespace ts {
if (relation === identityRelation) {
return propertiesIdenticalTo(source, target);
}
const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral);
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties);
if (unmatchedProperty) {
if (reportErrors) {
reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(unmatchedProperty), typeToString(source));
}
return Ternary.False;
}
let result = Ternary.True;
const properties = getPropertiesOfObjectType(target);
const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral);
for (const targetProp of properties) {
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
if (sourceProp !== targetProp) {
if (!sourceProp) {
if (!(targetProp.flags & SymbolFlags.Optional) || requireOptionalProperties) {
if (reportErrors) {
reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(targetProp), typeToString(source));
}
return Ternary.False;
}
}
else if (!(targetProp.flags & SymbolFlags.Prototype)) {
if (!(targetProp.flags & SymbolFlags.Prototype)) {
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
if (sourceProp && sourceProp !== targetProp) {
const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp);
const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp);
if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) {
@ -10463,17 +10462,17 @@ namespace ts {
}
}
function isPossiblyAssignableTo(source: Type, target: Type) {
function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean) {
const properties = getPropertiesOfObjectType(target);
for (const targetProp of properties) {
if (!(targetProp.flags & (SymbolFlags.Optional | SymbolFlags.Prototype))) {
const sourceProp = getPropertyOfObjectType(source, targetProp.escapedName);
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) {
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
if (!sourceProp) {
return false;
return targetProp;
}
}
}
return true;
return undefined;
}
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) {
@ -10671,7 +10670,7 @@ namespace ts {
}
// Infer from the members of source and target only if the two types are possibly related. We check
// in both directions because we may be inferring for a co-variant or a contra-variant position.
if (isPossiblyAssignableTo(source, target) || isPossiblyAssignableTo(target, source)) {
if (!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false) || !getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false)) {
inferFromProperties(source, target);
inferFromSignatures(source, target, SignatureKind.Call);
inferFromSignatures(source, target, SignatureKind.Construct);