diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ac1135788cd1c..6f352c95aec4d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7771,16 +7771,36 @@ namespace ts { if (target.flags & TypeFlags.Union && containsType(targetTypes, source)) { return Ternary.True; } - const len = targetTypes.length; - for (let i = 0; i < len; i++) { - const related = isRelatedTo(source, targetTypes[i], reportErrors && i === len - 1); + for (const type of targetTypes) { + const related = isRelatedTo(source, type, /*reportErrors*/ false); if (related) { return related; } } + if (reportErrors) { + const discriminantType = findMatchingDiscriminantType(source, target); + isRelatedTo(source, discriminantType || targetTypes[targetTypes.length - 1], /*reportErrors*/ true); + } return Ternary.False; } + function findMatchingDiscriminantType(source: Type, target: UnionOrIntersectionType) { + const sourceProperties = getPropertiesOfObjectType(source); + if (sourceProperties) { + for (const sourceProperty of sourceProperties) { + if (isDiscriminantProperty(target, sourceProperty.name)) { + const sourceType = getTypeOfSymbol(sourceProperty); + for (const type of target.types) { + const targetType = getTypeOfPropertyOfType(type, sourceProperty.name); + if (targetType && isRelatedTo(sourceType, targetType)) { + return type; + } + } + } + } + } + } + function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { let result = Ternary.True; const targetTypes = target.types; diff --git a/tests/baselines/reference/discriminatedUnionErrorMessage.errors.txt b/tests/baselines/reference/discriminatedUnionErrorMessage.errors.txt new file mode 100644 index 0000000000000..6f1eb511d3714 --- /dev/null +++ b/tests/baselines/reference/discriminatedUnionErrorMessage.errors.txt @@ -0,0 +1,23 @@ +tests/cases/compiler/discriminatedUnionErrorMessage.ts(8,5): error TS2322: Type '{ kind: "sq"; x: number; y: number; }' is not assignable to type 'Shape'. + Type '{ kind: "sq"; x: number; y: number; }' is not assignable to type 'Square'. + Property 'size' is missing in type '{ kind: "sq"; x: number; y: number; }'. + + +==== tests/cases/compiler/discriminatedUnionErrorMessage.ts (1 errors) ==== + type Square = { kind: "sq", size: number } + type Rectangle = { kind: "rt", x: number, y: number } + type Circle = { kind: "cr", radius: number } + type Shape = + | Square + | Rectangle + | Circle; + let shape: Shape = { + ~~~~~ +!!! error TS2322: Type '{ kind: "sq"; x: number; y: number; }' is not assignable to type 'Shape'. +!!! error TS2322: Type '{ kind: "sq"; x: number; y: number; }' is not assignable to type 'Square'. +!!! error TS2322: Property 'size' is missing in type '{ kind: "sq"; x: number; y: number; }'. + kind: "sq", + x: 12, + y: 13, + } + \ No newline at end of file diff --git a/tests/baselines/reference/discriminatedUnionErrorMessage.js b/tests/baselines/reference/discriminatedUnionErrorMessage.js new file mode 100644 index 0000000000000..10c94b19a4460 --- /dev/null +++ b/tests/baselines/reference/discriminatedUnionErrorMessage.js @@ -0,0 +1,21 @@ +//// [discriminatedUnionErrorMessage.ts] +type Square = { kind: "sq", size: number } +type Rectangle = { kind: "rt", x: number, y: number } +type Circle = { kind: "cr", radius: number } +type Shape = + | Square + | Rectangle + | Circle; +let shape: Shape = { + kind: "sq", + x: 12, + y: 13, +} + + +//// [discriminatedUnionErrorMessage.js] +var shape = { + kind: "sq", + x: 12, + y: 13 +}; diff --git a/tests/cases/compiler/discriminatedUnionErrorMessage.ts b/tests/cases/compiler/discriminatedUnionErrorMessage.ts new file mode 100644 index 0000000000000..eb2b08e9436ec --- /dev/null +++ b/tests/cases/compiler/discriminatedUnionErrorMessage.ts @@ -0,0 +1,12 @@ +type Square = { kind: "sq", size: number } +type Rectangle = { kind: "rt", x: number, y: number } +type Circle = { kind: "cr", radius: number } +type Shape = + | Square + | Rectangle + | Circle; +let shape: Shape = { + kind: "sq", + x: 12, + y: 13, +}