Skip to content

Commit f01cae8

Browse files
authored
Fixed an issue with missingType narrowing by case undefined in default cases (#58001)
1 parent 33b1561 commit f01cae8

10 files changed

Lines changed: 837 additions & 1 deletion

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28543,7 +28543,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2854328543
if (!hasDefaultClause) {
2854428544
return caseType;
2854528545
}
28546-
const defaultType = filterType(type, t => !(isUnitLikeType(t) && contains(switchTypes, getRegularTypeOfLiteralType(extractUnitType(t)))));
28546+
const defaultType = filterType(type, t => !(isUnitLikeType(t) && contains(switchTypes, t.flags & TypeFlags.Undefined ? undefinedType : getRegularTypeOfLiteralType(extractUnitType(t)))));
2854728547
return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]);
2854828548
}
2854928549

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] ////
2+
3+
=== narrowBySwitchDiscriminantUndefinedCase1.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/57999
5+
6+
interface A {
7+
>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0))
8+
9+
optionalProp?: "hello";
10+
>optionalProp : Symbol(A.optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 2, 13))
11+
}
12+
13+
function func(arg: A) {
14+
>func : Symbol(func, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 4, 1))
15+
>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14))
16+
>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0))
17+
18+
const { optionalProp } = arg;
19+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9))
20+
>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14))
21+
22+
switch (optionalProp) {
23+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9))
24+
25+
case undefined:
26+
>undefined : Symbol(undefined)
27+
28+
return undefined;
29+
>undefined : Symbol(undefined)
30+
31+
case "hello":
32+
return "hello";
33+
default:
34+
assertUnreachable(optionalProp);
35+
>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1))
36+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9))
37+
}
38+
}
39+
40+
function func2() {
41+
>func2 : Symbol(func2, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 17, 1))
42+
43+
const optionalProp = ["hello" as const][Math.random()];
44+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7))
45+
>const : Symbol(const)
46+
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
47+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
48+
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
49+
50+
switch (optionalProp) {
51+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7))
52+
53+
case undefined:
54+
>undefined : Symbol(undefined)
55+
56+
return undefined;
57+
>undefined : Symbol(undefined)
58+
59+
case "hello":
60+
return "hello";
61+
default:
62+
assertUnreachable(optionalProp);
63+
>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1))
64+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7))
65+
}
66+
}
67+
68+
function assertUnreachable(_: never): never {
69+
>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1))
70+
>_ : Symbol(_, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 32, 27))
71+
72+
throw new Error("Unreachable path taken");
73+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
74+
}
75+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] ////
2+
3+
=== narrowBySwitchDiscriminantUndefinedCase1.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/57999
5+
6+
interface A {
7+
optionalProp?: "hello";
8+
>optionalProp : "hello" | undefined
9+
> : ^^^^^^^^^^^^^^^^^^^
10+
}
11+
12+
function func(arg: A) {
13+
>func : (arg: A) => "hello" | undefined
14+
> : ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
15+
>arg : A
16+
> : ^
17+
18+
const { optionalProp } = arg;
19+
>optionalProp : "hello" | undefined
20+
> : ^^^^^^^^^^^^^^^^^^^
21+
>arg : A
22+
> : ^
23+
24+
switch (optionalProp) {
25+
>optionalProp : "hello" | undefined
26+
> : ^^^^^^^^^^^^^^^^^^^
27+
28+
case undefined:
29+
>undefined : undefined
30+
> : ^^^^^^^^^
31+
32+
return undefined;
33+
>undefined : undefined
34+
> : ^^^^^^^^^
35+
36+
case "hello":
37+
>"hello" : "hello"
38+
> : ^^^^^^^
39+
40+
return "hello";
41+
>"hello" : "hello"
42+
> : ^^^^^^^
43+
44+
default:
45+
assertUnreachable(optionalProp);
46+
>assertUnreachable(optionalProp) : never
47+
> : ^^^^^
48+
>assertUnreachable : (_: never) => never
49+
> : ^^^^^^^^^^^^^^^^^^^
50+
>optionalProp : never
51+
> : ^^^^^
52+
}
53+
}
54+
55+
function func2() {
56+
>func2 : () => "hello" | undefined
57+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
58+
59+
const optionalProp = ["hello" as const][Math.random()];
60+
>optionalProp : "hello"
61+
> : ^^^^^^^
62+
>["hello" as const][Math.random()] : "hello"
63+
> : ^^^^^^^
64+
>["hello" as const] : "hello"[]
65+
> : ^^^^^^^^^
66+
>"hello" as const : "hello"
67+
> : ^^^^^^^
68+
>"hello" : "hello"
69+
> : ^^^^^^^
70+
>Math.random() : number
71+
> : ^^^^^^
72+
>Math.random : () => number
73+
> : ^^^^^^^^^^^^
74+
>Math : Math
75+
> : ^^^^
76+
>random : () => number
77+
> : ^^^^^^^^^^^^
78+
79+
switch (optionalProp) {
80+
>optionalProp : "hello"
81+
> : ^^^^^^^
82+
83+
case undefined:
84+
>undefined : undefined
85+
> : ^^^^^^^^^
86+
87+
return undefined;
88+
>undefined : undefined
89+
> : ^^^^^^^^^
90+
91+
case "hello":
92+
>"hello" : "hello"
93+
> : ^^^^^^^
94+
95+
return "hello";
96+
>"hello" : "hello"
97+
> : ^^^^^^^
98+
99+
default:
100+
assertUnreachable(optionalProp);
101+
>assertUnreachable(optionalProp) : never
102+
> : ^^^^^
103+
>assertUnreachable : (_: never) => never
104+
> : ^^^^^^^^^^^^^^^^^^^
105+
>optionalProp : never
106+
> : ^^^^^
107+
}
108+
}
109+
110+
function assertUnreachable(_: never): never {
111+
>assertUnreachable : (_: never) => never
112+
> : ^^^^ ^^^^^
113+
>_ : never
114+
> : ^^^^^
115+
116+
throw new Error("Unreachable path taken");
117+
>new Error("Unreachable path taken") : Error
118+
> : ^^^^^
119+
>Error : ErrorConstructor
120+
> : ^^^^^^^^^^^^^^^^
121+
>"Unreachable path taken" : "Unreachable path taken"
122+
> : ^^^^^^^^^^^^^^^^^^^^^^^^
123+
}
124+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] ////
2+
3+
=== narrowBySwitchDiscriminantUndefinedCase1.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/57999
5+
6+
interface A {
7+
>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0))
8+
9+
optionalProp?: "hello";
10+
>optionalProp : Symbol(A.optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 2, 13))
11+
}
12+
13+
function func(arg: A) {
14+
>func : Symbol(func, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 4, 1))
15+
>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14))
16+
>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0))
17+
18+
const { optionalProp } = arg;
19+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9))
20+
>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14))
21+
22+
switch (optionalProp) {
23+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9))
24+
25+
case undefined:
26+
>undefined : Symbol(undefined)
27+
28+
return undefined;
29+
>undefined : Symbol(undefined)
30+
31+
case "hello":
32+
return "hello";
33+
default:
34+
assertUnreachable(optionalProp);
35+
>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1))
36+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9))
37+
}
38+
}
39+
40+
function func2() {
41+
>func2 : Symbol(func2, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 17, 1))
42+
43+
const optionalProp = ["hello" as const][Math.random()];
44+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7))
45+
>const : Symbol(const)
46+
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
47+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
48+
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
49+
50+
switch (optionalProp) {
51+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7))
52+
53+
case undefined:
54+
>undefined : Symbol(undefined)
55+
56+
return undefined;
57+
>undefined : Symbol(undefined)
58+
59+
case "hello":
60+
return "hello";
61+
default:
62+
assertUnreachable(optionalProp);
63+
>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1))
64+
>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7))
65+
}
66+
}
67+
68+
function assertUnreachable(_: never): never {
69+
>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1))
70+
>_ : Symbol(_, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 32, 27))
71+
72+
throw new Error("Unreachable path taken");
73+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
74+
}
75+

0 commit comments

Comments
 (0)