Only infer from constituents with matching discriminants in unions

This commit is contained in:
Anders Hejlsberg 2018-12-05 11:46:06 -08:00
parent 07dbc56208
commit 676d8af43a

View File

@ -12473,10 +12473,10 @@ namespace ts {
return propertiesIdenticalTo(source, target);
}
const requireOptionalProperties = relation === subtypeRelation && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source);
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties);
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false);
if (unmatchedProperty) {
if (reportErrors) {
const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties));
const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false));
if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code &&
headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) {
suppressNextError = true; // Retain top-level error for interface implementing issues, otherwise omit it
@ -13900,7 +13900,7 @@ namespace ts {
return getTypeFromInference(inference);
}
function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean) {
function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean) {
const properties = target.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(<IntersectionType>target) : getPropertiesOfObjectType(target);
for (const targetProp of properties) {
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) {
@ -13908,12 +13908,21 @@ namespace ts {
if (!sourceProp) {
yield targetProp;
}
else if (matchDiscriminantProperties) {
const targetType = getTypeOfSymbol(targetProp);
if (targetType.flags & TypeFlags.Unit) {
const sourceType = getTypeOfSymbol(sourceProp);
if (!(sourceType.flags & TypeFlags.Any || getRegularTypeOfLiteralType(sourceType) === getRegularTypeOfLiteralType(targetType))) {
yield targetProp;
}
}
}
}
}
}
function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean): Symbol | undefined {
return getUnmatchedProperties(source, target, requireOptionalProperties).next().value;
function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): Symbol | undefined {
return getUnmatchedProperties(source, target, requireOptionalProperties, matchDiscriminantProperties).next().value;
}
function tupleTypesDefinitelyUnrelated(source: TupleTypeReference, target: TupleTypeReference) {
@ -13925,7 +13934,8 @@ namespace ts {
// Two tuple types with incompatible arities are definitely unrelated.
// Two object types that each have a property that is unmatched in the other are definitely unrelated.
return isTupleType(source) && isTupleType(target) && tupleTypesDefinitelyUnrelated(source, target) ||
!!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false) && !!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false);
!!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ true) &&
!!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ true);
}
function getTypeFromInference(inference: InferenceInfo) {