diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ed44d8b4140..f76f1b318e9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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(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) {