Merge pull request #18126 from Microsoft/propertyRelations

Compare shapes of objects before comparing contained types
This commit is contained in:
Anders Hejlsberg
2017-09-03 20:33:58 +01:00
committed by GitHub
8 changed files with 43 additions and 92 deletions

View File

@@ -9436,21 +9436,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) {
@@ -10475,17 +10474,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) {
@@ -10683,7 +10682,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);