mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Correct excess property error on ambiguous discriminated unions
This commit is contained in:
@@ -9029,6 +9029,7 @@ namespace ts {
|
||||
|
||||
function findMatchingDiscriminantType(source: Type, target: UnionOrIntersectionType) {
|
||||
const sourceProperties = getPropertiesOfObjectType(source);
|
||||
let match: Type;
|
||||
if (sourceProperties) {
|
||||
for (const sourceProperty of sourceProperties) {
|
||||
if (isDiscriminantProperty(target, sourceProperty.name)) {
|
||||
@@ -9036,12 +9037,16 @@ namespace ts {
|
||||
for (const type of target.types) {
|
||||
const targetType = getTypeOfPropertyOfType(type, sourceProperty.name);
|
||||
if (targetType && isRelatedTo(sourceType, targetType)) {
|
||||
return type;
|
||||
if (match) {
|
||||
return undefined;
|
||||
}
|
||||
match = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
function typeRelatedToEachType(source: Type, target: IntersectionType, reportErrors: boolean): Ternary {
|
||||
|
||||
@@ -5,9 +5,21 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(11,21): error TS2322: Type
|
||||
tests/cases/compiler/excessPropertyCheckWithUnions.ts(12,1): error TS2322: Type '{ tag: "D"; }' is not assignable to type 'ADT'.
|
||||
Type '{ tag: "D"; }' is not assignable to type '{ tag: "D"; d20: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; }'.
|
||||
Property 'd20' is missing in type '{ tag: "D"; }'.
|
||||
tests/cases/compiler/excessPropertyCheckWithUnions.ts(33,28): error TS2322: Type '{ tag: "A"; x: string; extra: number; }' is not assignable to type 'Ambiguous'.
|
||||
Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'.
|
||||
tests/cases/compiler/excessPropertyCheckWithUnions.ts(34,26): error TS2322: Type '{ tag: "A"; y: number; extra: number; }' is not assignable to type 'Ambiguous'.
|
||||
Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'.
|
||||
tests/cases/compiler/excessPropertyCheckWithUnions.ts(39,1): error TS2322: Type '{ tag: "A"; }' is not assignable to type 'Ambiguous'.
|
||||
Type '{ tag: "A"; }' is not assignable to type '{ tag: "C"; }'.
|
||||
Types of property 'tag' are incompatible.
|
||||
Type '"A"' is not assignable to type '"C"'.
|
||||
tests/cases/compiler/excessPropertyCheckWithUnions.ts(40,1): error TS2322: Type '{ tag: "A"; z: true; }' is not assignable to type 'Ambiguous'.
|
||||
Type '{ tag: "A"; z: true; }' is not assignable to type '{ tag: "C"; }'.
|
||||
Types of property 'tag' are incompatible.
|
||||
Type '"A"' is not assignable to type '"C"'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/excessPropertyCheckWithUnions.ts (3 errors) ====
|
||||
==== tests/cases/compiler/excessPropertyCheckWithUnions.ts (7 errors) ====
|
||||
type ADT = {
|
||||
tag: "A",
|
||||
a1: string
|
||||
@@ -30,4 +42,48 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(12,1): error TS2322: Type
|
||||
!!! error TS2322: Type '{ tag: "D"; }' is not assignable to type 'ADT'.
|
||||
!!! error TS2322: Type '{ tag: "D"; }' is not assignable to type '{ tag: "D"; d20: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; }'.
|
||||
!!! error TS2322: Property 'd20' is missing in type '{ tag: "D"; }'.
|
||||
|
||||
type Ambiguous = {
|
||||
tag: "A",
|
||||
x: string
|
||||
} | {
|
||||
tag: "A",
|
||||
y: number
|
||||
} | {
|
||||
tag: "B",
|
||||
z: boolean
|
||||
} | {
|
||||
tag: "C"
|
||||
}
|
||||
let amb: Ambiguous
|
||||
// no error for ambiguous tag, even when it could satisfy both constituents at once
|
||||
amb = { tag: "A", x: "hi" }
|
||||
amb = { tag: "A", y: 12 }
|
||||
amb = { tag: "A", x: "hi", y: 12 }
|
||||
|
||||
// correctly error on excess property 'extra', even when ambiguous
|
||||
amb = { tag: "A", x: "hi", extra: 12 }
|
||||
~~~~~~~~~
|
||||
!!! error TS2322: Type '{ tag: "A"; x: string; extra: number; }' is not assignable to type 'Ambiguous'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'.
|
||||
amb = { tag: "A", y: 12, extra: 12 }
|
||||
~~~~~~~~~
|
||||
!!! error TS2322: Type '{ tag: "A"; y: number; extra: number; }' is not assignable to type 'Ambiguous'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'.
|
||||
|
||||
// assignability errors still work.
|
||||
// But note that the error for `z: true` is the fallback one of reporting on
|
||||
// the last constituent since assignability error reporting can't find a single best discriminant either.
|
||||
amb = { tag: "A" }
|
||||
~~~
|
||||
!!! error TS2322: Type '{ tag: "A"; }' is not assignable to type 'Ambiguous'.
|
||||
!!! error TS2322: Type '{ tag: "A"; }' is not assignable to type '{ tag: "C"; }'.
|
||||
!!! error TS2322: Types of property 'tag' are incompatible.
|
||||
!!! error TS2322: Type '"A"' is not assignable to type '"C"'.
|
||||
amb = { tag: "A", z: true }
|
||||
~~~
|
||||
!!! error TS2322: Type '{ tag: "A"; z: true; }' is not assignable to type 'Ambiguous'.
|
||||
!!! error TS2322: Type '{ tag: "A"; z: true; }' is not assignable to type '{ tag: "C"; }'.
|
||||
!!! error TS2322: Types of property 'tag' are incompatible.
|
||||
!!! error TS2322: Type '"A"' is not assignable to type '"C"'.
|
||||
|
||||
@@ -11,9 +11,50 @@ type ADT = {
|
||||
let wrong: ADT = { tag: "T", a1: "extra" }
|
||||
wrong = { tag: "A", d20: 12 }
|
||||
wrong = { tag: "D" }
|
||||
|
||||
type Ambiguous = {
|
||||
tag: "A",
|
||||
x: string
|
||||
} | {
|
||||
tag: "A",
|
||||
y: number
|
||||
} | {
|
||||
tag: "B",
|
||||
z: boolean
|
||||
} | {
|
||||
tag: "C"
|
||||
}
|
||||
let amb: Ambiguous
|
||||
// no error for ambiguous tag, even when it could satisfy both constituents at once
|
||||
amb = { tag: "A", x: "hi" }
|
||||
amb = { tag: "A", y: 12 }
|
||||
amb = { tag: "A", x: "hi", y: 12 }
|
||||
|
||||
// correctly error on excess property 'extra', even when ambiguous
|
||||
amb = { tag: "A", x: "hi", extra: 12 }
|
||||
amb = { tag: "A", y: 12, extra: 12 }
|
||||
|
||||
// assignability errors still work.
|
||||
// But note that the error for `z: true` is the fallback one of reporting on
|
||||
// the last constituent since assignability error reporting can't find a single best discriminant either.
|
||||
amb = { tag: "A" }
|
||||
amb = { tag: "A", z: true }
|
||||
|
||||
|
||||
//// [excessPropertyCheckWithUnions.js]
|
||||
var wrong = { tag: "T", a1: "extra" };
|
||||
wrong = { tag: "A", d20: 12 };
|
||||
wrong = { tag: "D" };
|
||||
var amb;
|
||||
// no error for ambiguous tag, even when it could satisfy both constituents at once
|
||||
amb = { tag: "A", x: "hi" };
|
||||
amb = { tag: "A", y: 12 };
|
||||
amb = { tag: "A", x: "hi", y: 12 };
|
||||
// correctly error on excess property 'extra', even when ambiguous
|
||||
amb = { tag: "A", x: "hi", extra: 12 };
|
||||
amb = { tag: "A", y: 12, extra: 12 };
|
||||
// assignability errors still work.
|
||||
// But note that the error for `z: true` is the fallback one of reporting on
|
||||
// the last constituent since assignability error reporting can't find a single best discriminant either.
|
||||
amb = { tag: "A" };
|
||||
amb = { tag: "A", z: true };
|
||||
|
||||
@@ -10,3 +10,31 @@ type ADT = {
|
||||
let wrong: ADT = { tag: "T", a1: "extra" }
|
||||
wrong = { tag: "A", d20: 12 }
|
||||
wrong = { tag: "D" }
|
||||
|
||||
type Ambiguous = {
|
||||
tag: "A",
|
||||
x: string
|
||||
} | {
|
||||
tag: "A",
|
||||
y: number
|
||||
} | {
|
||||
tag: "B",
|
||||
z: boolean
|
||||
} | {
|
||||
tag: "C"
|
||||
}
|
||||
let amb: Ambiguous
|
||||
// no error for ambiguous tag, even when it could satisfy both constituents at once
|
||||
amb = { tag: "A", x: "hi" }
|
||||
amb = { tag: "A", y: 12 }
|
||||
amb = { tag: "A", x: "hi", y: 12 }
|
||||
|
||||
// correctly error on excess property 'extra', even when ambiguous
|
||||
amb = { tag: "A", x: "hi", extra: 12 }
|
||||
amb = { tag: "A", y: 12, extra: 12 }
|
||||
|
||||
// assignability errors still work.
|
||||
// But note that the error for `z: true` is the fallback one of reporting on
|
||||
// the last constituent since assignability error reporting can't find a single best discriminant either.
|
||||
amb = { tag: "A" }
|
||||
amb = { tag: "A", z: true }
|
||||
|
||||
Reference in New Issue
Block a user