Skip to content

Commit f93cc34

Browse files
committed
Consider all union types matching discriminator for excess property checks
Fixes microsoft#51873
1 parent 790c03d commit f93cc34

12 files changed

+180
-198
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22048,15 +22048,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2204822048
if (match === -1) {
2204922049
return defaultValue;
2205022050
}
22051-
// make sure exactly 1 matches before returning it
22052-
let nextMatch = discriminable.indexOf(/*searchElement*/ true, match + 1);
22053-
while (nextMatch !== -1) {
22054-
if (!isTypeIdenticalTo(target.types[match], target.types[nextMatch])) {
22055-
return defaultValue;
22056-
}
22057-
nextMatch = discriminable.indexOf(/*searchElement*/ true, nextMatch + 1);
22058-
}
22059-
return target.types[match];
22051+
return getUnionType(target.types.filter((_, index) => discriminable[index]));
2206022052
}
2206122053

2206222054
/**

tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.errors.txt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(30,5): erro
22
Object literal may only specify known properties, and 'multipleOf' does not exist in type 'Float'.
33
tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(41,5): error TS2322: Type '{ p1: "left"; p2: false; p3: number; p4: string; }' is not assignable to type 'DisjointDiscriminants'.
44
Object literal may only specify known properties, and 'p3' does not exist in type '{ p1: "left"; p2: boolean; }'.
5+
tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(50,5): error TS2322: Type '{ p1: "left"; p2: true; p3: number; p4: string; }' is not assignable to type 'DisjointDiscriminants'.
6+
Object literal may only specify known properties, and 'p4' does not exist in type '{ p1: "left"; p2: true; p3: number; } | { p1: "left"; p2: boolean; }'.
57
tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(57,5): error TS2322: Type '{ p1: "right"; p2: false; p3: number; p4: string; }' is not assignable to type 'DisjointDiscriminants'.
68
Object literal may only specify known properties, and 'p3' does not exist in type '{ p1: "right"; p2: false; p4: string; }'.
79

810

9-
==== tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts (3 errors) ====
11+
==== tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts (4 errors) ====
1012
// Repro from #32657
1113

1214
interface Base<T> {
@@ -57,12 +59,15 @@ tests/cases/compiler/excessPropertyCheckWithMultipleDiscriminants.ts(57,5): erro
5759
p4: "hello"
5860
};
5961

60-
// This has no excess error because variant one and three are both applicable.
62+
// This has excess error because variant two is not applicable.
6163
const b: DisjointDiscriminants = {
6264
p1: 'left',
6365
p2: true,
6466
p3: 42,
6567
p4: "hello"
68+
~~~~~~~~~~~
69+
!!! error TS2322: Type '{ p1: "left"; p2: true; p3: number; p4: string; }' is not assignable to type 'DisjointDiscriminants'.
70+
!!! error TS2322: Object literal may only specify known properties, and 'p4' does not exist in type '{ p1: "left"; p2: true; p3: number; } | { p1: "left"; p2: boolean; }'.
6671
};
6772

6873
// This has excess error because variant two is the only applicable case

tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const a: DisjointDiscriminants = {
4343
p4: "hello"
4444
};
4545

46-
// This has no excess error because variant one and three are both applicable.
46+
// This has excess error because variant two is not applicable.
4747
const b: DisjointDiscriminants = {
4848
p1: 'left',
4949
p2: true,
@@ -75,7 +75,7 @@ var a = {
7575
p3: 42,
7676
p4: "hello"
7777
};
78-
// This has no excess error because variant one and three are both applicable.
78+
// This has excess error because variant two is not applicable.
7979
var b = {
8080
p1: 'left',
8181
p2: true,

tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.symbols

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ const a: DisjointDiscriminants = {
103103

104104
};
105105

106-
// This has no excess error because variant one and three are both applicable.
106+
// This has excess error because variant two is not applicable.
107107
const b: DisjointDiscriminants = {
108108
>b : Symbol(b, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 45, 5))
109109
>DisjointDiscriminants : Symbol(DisjointDiscriminants, Decl(excessPropertyCheckWithMultipleDiscriminants.ts, 31, 1))

tests/baselines/reference/excessPropertyCheckWithMultipleDiscriminants.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ const a: DisjointDiscriminants = {
9393

9494
};
9595

96-
// This has no excess error because variant one and three are both applicable.
96+
// This has excess error because variant two is not applicable.
9797
const b: DisjointDiscriminants = {
9898
>b : DisjointDiscriminants
9999
>{ p1: 'left', p2: true, p3: 42, p4: "hello"} : { p1: "left"; p2: true; p3: number; p4: string; }

tests/baselines/reference/excessPropertyCheckWithUnions.errors.txt

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,27 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(11,21): error TS2322: Type
55
tests/cases/compiler/excessPropertyCheckWithUnions.ts(12,1): error TS2322: Type '{ tag: "D"; }' is not assignable to type 'ADT'.
66
Property 'd20' is missing in type '{ tag: "D"; }' but required in type '{ tag: "D"; d20: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; }'.
77
tests/cases/compiler/excessPropertyCheckWithUnions.ts(33,28): error TS2322: Type '{ tag: "A"; x: string; extra: number; }' is not assignable to type 'Ambiguous'.
8-
Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'.
8+
Object literal may only specify known properties, and 'extra' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'.
99
tests/cases/compiler/excessPropertyCheckWithUnions.ts(34,26): error TS2322: Type '{ tag: "A"; y: number; extra: number; }' is not assignable to type 'Ambiguous'.
10-
Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'.
11-
tests/cases/compiler/excessPropertyCheckWithUnions.ts(39,1): error TS2322: Type '{ tag: "A"; }' is not assignable to type 'Ambiguous'.
12-
Type '{ tag: "A"; }' is not assignable to type '{ tag: "C"; }'.
13-
Types of property 'tag' are incompatible.
14-
Type '"A"' is not assignable to type '"C"'.
15-
tests/cases/compiler/excessPropertyCheckWithUnions.ts(40,1): error TS2322: Type '{ tag: "A"; z: true; }' is not assignable to type 'Ambiguous'.
16-
Type '{ tag: "A"; z: true; }' is not assignable to type '{ tag: "B"; z: boolean; }'.
17-
Types of property 'tag' are incompatible.
18-
Type '"A"' is not assignable to type '"B"'.
19-
tests/cases/compiler/excessPropertyCheckWithUnions.ts(49,35): error TS2322: Type '{ a: 1; b: 1; first: string; second: string; }' is not assignable to type 'Overlapping'.
10+
Object literal may only specify known properties, and 'extra' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'.
11+
tests/cases/compiler/excessPropertyCheckWithUnions.ts(37,1): error TS2322: Type '{ tag: "A"; }' is not assignable to type 'Ambiguous'.
12+
Type '{ tag: "A"; }' is not assignable to type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'.
13+
Property 'y' is missing in type '{ tag: "A"; }' but required in type '{ tag: "A"; y: number; }'.
14+
tests/cases/compiler/excessPropertyCheckWithUnions.ts(38,19): error TS2322: Type '{ tag: "A"; z: boolean; }' is not assignable to type 'Ambiguous'.
15+
Object literal may only specify known properties, and 'z' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'.
16+
tests/cases/compiler/excessPropertyCheckWithUnions.ts(47,35): error TS2322: Type '{ a: 1; b: 1; first: string; second: string; }' is not assignable to type 'Overlapping'.
2017
Object literal may only specify known properties, and 'second' does not exist in type '{ a: 1; b: 1; first: string; }'.
21-
tests/cases/compiler/excessPropertyCheckWithUnions.ts(50,35): error TS2322: Type '{ a: 1; b: 1; first: string; third: string; }' is not assignable to type 'Overlapping'.
18+
tests/cases/compiler/excessPropertyCheckWithUnions.ts(48,35): error TS2322: Type '{ a: 1; b: 1; first: string; third: string; }' is not assignable to type 'Overlapping'.
2219
Object literal may only specify known properties, and 'third' does not exist in type '{ a: 1; b: 1; first: string; }'.
23-
tests/cases/compiler/excessPropertyCheckWithUnions.ts(66,9): error TS2322: Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type 'AB'.
20+
tests/cases/compiler/excessPropertyCheckWithUnions.ts(64,9): error TS2322: Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type 'AB'.
2421
Types of property 'n' are incompatible.
2522
Type '{ a: string; b: string; }' is not assignable to type 'AN'.
2623
Object literal may only specify known properties, and 'b' does not exist in type 'AN'.
27-
tests/cases/compiler/excessPropertyCheckWithUnions.ts(87,5): error TS2322: Type '{ tag: "button"; type: "submit"; href: string; }' is not assignable to type 'Union'.
24+
tests/cases/compiler/excessPropertyCheckWithUnions.ts(85,5): error TS2322: Type '{ tag: "button"; type: "submit"; href: string; }' is not assignable to type 'Union'.
2825
Object literal may only specify known properties, and 'href' does not exist in type 'Button'.
29-
tests/cases/compiler/excessPropertyCheckWithUnions.ts(108,5): error TS2322: Type 'string' is not assignable to type 'IValue'.
30-
tests/cases/compiler/excessPropertyCheckWithUnions.ts(113,67): error TS2322: Type 'string' is not assignable to type 'number'.
31-
tests/cases/compiler/excessPropertyCheckWithUnions.ts(114,63): error TS2322: Type 'string' is not assignable to type 'number'.
26+
tests/cases/compiler/excessPropertyCheckWithUnions.ts(106,5): error TS2322: Type 'string' is not assignable to type 'IValue'.
27+
tests/cases/compiler/excessPropertyCheckWithUnions.ts(111,67): error TS2322: Type 'string' is not assignable to type 'number'.
28+
tests/cases/compiler/excessPropertyCheckWithUnions.ts(112,63): error TS2322: Type 'string' is not assignable to type 'number'.
3229

3330

3431
==== tests/cases/compiler/excessPropertyCheckWithUnions.ts (14 errors) ====
@@ -77,27 +74,23 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(114,63): error TS2322: Typ
7774
amb = { tag: "A", x: "hi", extra: 12 }
7875
~~~~~~~~~
7976
!!! error TS2322: Type '{ tag: "A"; x: string; extra: number; }' is not assignable to type 'Ambiguous'.
80-
!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'.
77+
!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'.
8178
amb = { tag: "A", y: 12, extra: 12 }
8279
~~~~~~~~~
8380
!!! error TS2322: Type '{ tag: "A"; y: number; extra: number; }' is not assignable to type 'Ambiguous'.
84-
!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type 'Ambiguous'.
81+
!!! error TS2322: Object literal may only specify known properties, and 'extra' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'.
8582

86-
// assignability errors still work.
87-
// But note that the error for `z: true` is the fallback one of reporting on
88-
// the last constituent since assignability error reporting can't find a single best discriminant either.
83+
// assignability errors still work
8984
amb = { tag: "A" }
9085
~~~
9186
!!! error TS2322: Type '{ tag: "A"; }' is not assignable to type 'Ambiguous'.
92-
!!! error TS2322: Type '{ tag: "A"; }' is not assignable to type '{ tag: "C"; }'.
93-
!!! error TS2322: Types of property 'tag' are incompatible.
94-
!!! error TS2322: Type '"A"' is not assignable to type '"C"'.
87+
!!! error TS2322: Type '{ tag: "A"; }' is not assignable to type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'.
88+
!!! error TS2322: Property 'y' is missing in type '{ tag: "A"; }' but required in type '{ tag: "A"; y: number; }'.
89+
!!! related TS2728 tests/cases/compiler/excessPropertyCheckWithUnions.ts:19:5: 'y' is declared here.
9590
amb = { tag: "A", z: true }
96-
~~~
97-
!!! error TS2322: Type '{ tag: "A"; z: true; }' is not assignable to type 'Ambiguous'.
98-
!!! error TS2322: Type '{ tag: "A"; z: true; }' is not assignable to type '{ tag: "B"; z: boolean; }'.
99-
!!! error TS2322: Types of property 'tag' are incompatible.
100-
!!! error TS2322: Type '"A"' is not assignable to type '"B"'.
91+
~~~~~~~
92+
!!! error TS2322: Type '{ tag: "A"; z: boolean; }' is not assignable to type 'Ambiguous'.
93+
!!! error TS2322: Object literal may only specify known properties, and 'z' does not exist in type '{ tag: "A"; x: string; } | { tag: "A"; y: number; }'.
10194

10295
type Overlapping =
10396
| { a: 1, b: 1, first: string }
@@ -167,7 +160,7 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(114,63): error TS2322: Typ
167160
value: string
168161
}
169162

170-
interface StringKeys {
163+
interface StringKeys {
171164
[propertyName: string]: IValue;
172165
};
173166

tests/baselines/reference/excessPropertyCheckWithUnions.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ amb = { tag: "A", x: "hi", y: 12 }
3434
amb = { tag: "A", x: "hi", extra: 12 }
3535
amb = { tag: "A", y: 12, extra: 12 }
3636

37-
// assignability errors still work.
38-
// But note that the error for `z: true` is the fallback one of reporting on
39-
// the last constituent since assignability error reporting can't find a single best discriminant either.
37+
// assignability errors still work
4038
amb = { tag: "A" }
4139
amb = { tag: "A", z: true }
4240

@@ -94,7 +92,7 @@ interface IValue {
9492
value: string
9593
}
9694

97-
interface StringKeys {
95+
interface StringKeys {
9896
[propertyName: string]: IValue;
9997
};
10098

@@ -178,9 +176,7 @@ amb = { tag: "A", x: "hi", y: 12 };
178176
// correctly error on excess property 'extra', even when ambiguous
179177
amb = { tag: "A", x: "hi", extra: 12 };
180178
amb = { tag: "A", y: 12, extra: 12 };
181-
// assignability errors still work.
182-
// But note that the error for `z: true` is the fallback one of reporting on
183-
// the last constituent since assignability error reporting can't find a single best discriminant either.
179+
// assignability errors still work
184180
amb = { tag: "A" };
185181
amb = { tag: "A", z: true };
186182
var over;

0 commit comments

Comments
 (0)