Skip to content

Commit 97c5587

Browse files
committed
Filter discriminants of type never
1 parent 038d951 commit 97c5587

File tree

6 files changed

+215
-1
lines changed

6 files changed

+215
-1
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17363,7 +17363,14 @@ namespace ts {
1736317363
}
1736417364
const propType = getTypeOfPropertyOfType(type, propName);
1736517365
const narrowedPropType = propType && narrowType(propType);
17366-
return propType === narrowedPropType ? type : filterType(type, t => isTypeComparableTo(getTypeOfPropertyOrIndexSignature(t, propName), narrowedPropType!));
17366+
if (propType === narrowedPropType) {
17367+
return type;
17368+
}
17369+
const isPropertyDiscriminated = (t: Type) => {
17370+
const constituentPropType = getTypeOfPropertyOrIndexSignature(t, propName);
17371+
return (constituentPropType.flags & TypeFlags.Never) === 0 && isTypeComparableTo(constituentPropType, narrowedPropType!);
17372+
};
17373+
return filterType(type, isPropertyDiscriminated);
1736717374
}
1736817375

1736917376
function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type {

tests/baselines/reference/discriminatedUnionTypes2.errors.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,27 @@ tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(32,11): error TS
105105
foo;
106106
}
107107
}
108+
109+
// Repro from #33448
110+
111+
type a = {
112+
type: 'a',
113+
data: string
114+
}
115+
type b = {
116+
type: 'b',
117+
name: string
118+
}
119+
type c = {
120+
type: 'c',
121+
other: string
122+
}
123+
type abc = a | b | c;
124+
function f(problem: abc & (b | c)) {
125+
if (problem.type === 'b') {
126+
console.log(problem.name);
127+
} else {
128+
console.log(problem.other);
129+
}
130+
}
108131

tests/baselines/reference/discriminatedUnionTypes2.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,29 @@ function f31(foo: Foo) {
9393
foo;
9494
}
9595
}
96+
97+
// Repro from #33448
98+
99+
type a = {
100+
type: 'a',
101+
data: string
102+
}
103+
type b = {
104+
type: 'b',
105+
name: string
106+
}
107+
type c = {
108+
type: 'c',
109+
other: string
110+
}
111+
type abc = a | b | c;
112+
function f(problem: abc & (b | c)) {
113+
if (problem.type === 'b') {
114+
console.log(problem.name);
115+
} else {
116+
console.log(problem.other);
117+
}
118+
}
96119

97120

98121
//// [discriminatedUnionTypes2.js]
@@ -164,3 +187,11 @@ function f31(foo) {
164187
foo;
165188
}
166189
}
190+
function f(problem) {
191+
if (problem.type === 'b') {
192+
console.log(problem.name);
193+
}
194+
else {
195+
console.log(problem.other);
196+
}
197+
}

tests/baselines/reference/discriminatedUnionTypes2.symbols

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,69 @@ function f31(foo: Foo) {
273273
}
274274
}
275275

276+
// Repro from #33448
277+
278+
type a = {
279+
>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 93, 1))
280+
281+
type: 'a',
282+
>type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 97, 10))
283+
284+
data: string
285+
>data : Symbol(data, Decl(discriminatedUnionTypes2.ts, 98, 14))
286+
}
287+
type b = {
288+
>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 100, 1))
289+
290+
type: 'b',
291+
>type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 101, 10))
292+
293+
name: string
294+
>name : Symbol(name, Decl(discriminatedUnionTypes2.ts, 102, 14))
295+
}
296+
type c = {
297+
>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 104, 1))
298+
299+
type: 'c',
300+
>type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 105, 10))
301+
302+
other: string
303+
>other : Symbol(other, Decl(discriminatedUnionTypes2.ts, 106, 14))
304+
}
305+
type abc = a | b | c;
306+
>abc : Symbol(abc, Decl(discriminatedUnionTypes2.ts, 108, 1))
307+
>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 93, 1))
308+
>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 100, 1))
309+
>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 104, 1))
310+
311+
function f(problem: abc & (b | c)) {
312+
>f : Symbol(f, Decl(discriminatedUnionTypes2.ts, 109, 21))
313+
>problem : Symbol(problem, Decl(discriminatedUnionTypes2.ts, 110, 11))
314+
>abc : Symbol(abc, Decl(discriminatedUnionTypes2.ts, 108, 1))
315+
>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 100, 1))
316+
>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 104, 1))
317+
318+
if (problem.type === 'b') {
319+
>problem.type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 105, 10), Decl(discriminatedUnionTypes2.ts, 97, 10), Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 97, 10) ... and 5 more)
320+
>problem : Symbol(problem, Decl(discriminatedUnionTypes2.ts, 110, 11))
321+
>type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 105, 10), Decl(discriminatedUnionTypes2.ts, 97, 10), Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 97, 10) ... and 5 more)
322+
323+
console.log(problem.name);
324+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
325+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
326+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
327+
>problem.name : Symbol(name, Decl(discriminatedUnionTypes2.ts, 102, 14))
328+
>problem : Symbol(problem, Decl(discriminatedUnionTypes2.ts, 110, 11))
329+
>name : Symbol(name, Decl(discriminatedUnionTypes2.ts, 102, 14))
330+
331+
} else {
332+
console.log(problem.other);
333+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
334+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
335+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
336+
>problem.other : Symbol(other, Decl(discriminatedUnionTypes2.ts, 106, 14))
337+
>problem : Symbol(problem, Decl(discriminatedUnionTypes2.ts, 110, 11))
338+
>other : Symbol(other, Decl(discriminatedUnionTypes2.ts, 106, 14))
339+
}
340+
}
341+

tests/baselines/reference/discriminatedUnionTypes2.types

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,67 @@ function f31(foo: Foo) {
289289
}
290290
}
291291

292+
// Repro from #33448
293+
294+
type a = {
295+
>a : a
296+
297+
type: 'a',
298+
>type : "a"
299+
300+
data: string
301+
>data : string
302+
}
303+
type b = {
304+
>b : b
305+
306+
type: 'b',
307+
>type : "b"
308+
309+
name: string
310+
>name : string
311+
}
312+
type c = {
313+
>c : c
314+
315+
type: 'c',
316+
>type : "c"
317+
318+
other: string
319+
>other : string
320+
}
321+
type abc = a | b | c;
322+
>abc : abc
323+
324+
function f(problem: abc & (b | c)) {
325+
>f : (problem: b | c | (a & b) | (a & c) | (b & c) | (c & b)) => void
326+
>problem : b | c | (a & b) | (a & c) | (b & c) | (c & b)
327+
328+
if (problem.type === 'b') {
329+
>problem.type === 'b' : boolean
330+
>problem.type : "b" | "c"
331+
>problem : b | c | (a & b) | (a & c) | (b & c) | (c & b)
332+
>type : "b" | "c"
333+
>'b' : "b"
334+
335+
console.log(problem.name);
336+
>console.log(problem.name) : void
337+
>console.log : (message?: any, ...optionalParams: any[]) => void
338+
>console : Console
339+
>log : (message?: any, ...optionalParams: any[]) => void
340+
>problem.name : string
341+
>problem : b
342+
>name : string
343+
344+
} else {
345+
console.log(problem.other);
346+
>console.log(problem.other) : void
347+
>console.log : (message?: any, ...optionalParams: any[]) => void
348+
>console : Console
349+
>log : (message?: any, ...optionalParams: any[]) => void
350+
>problem.other : string
351+
>problem : c
352+
>other : string
353+
}
354+
}
355+

tests/cases/conformance/types/union/discriminatedUnionTypes2.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,26 @@ function f31(foo: Foo) {
9494
foo;
9595
}
9696
}
97+
98+
// Repro from #33448
99+
100+
type a = {
101+
type: 'a',
102+
data: string
103+
}
104+
type b = {
105+
type: 'b',
106+
name: string
107+
}
108+
type c = {
109+
type: 'c',
110+
other: string
111+
}
112+
type abc = a | b | c;
113+
function f(problem: abc & (b | c)) {
114+
if (problem.type === 'b') {
115+
console.log(problem.name);
116+
} else {
117+
console.log(problem.other);
118+
}
119+
}

0 commit comments

Comments
 (0)