Skip to content

Commit 71661b9

Browse files
Fixed issue where non null assertion caused getFlowTypeOfReference to return the declared type if the type was already narrowed to never. (#35863)
This was caused by the fact that getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull) will return never both if resultType was already never and if resultType does not contain undefined or null. In the latter case returning the declaring type is correct, in the former case this causes something narrowed to never to still be typed as the original declared type.
1 parent 3d6650e commit 71661b9

File tree

6 files changed

+107
-4
lines changed

6 files changed

+107
-4
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22447,7 +22447,7 @@ namespace ts {
2244722447
// on empty arrays are possible without implicit any errors and new element types can be inferred without
2244822448
// type mismatch errors.
2244922449
const resultType = getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) ? autoArrayType : finalizeEvolvingArrayType(evolvedType);
22450-
if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
22450+
if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && !(resultType.flags & TypeFlags.Never) && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
2245122451
return declaredType;
2245222452
}
2245322453
return resultType;

tests/baselines/reference/exhaustiveSwitchStatements1.errors.txt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(7,9): error TS7027: Unreachable code detected.
22
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(235,5): error TS2367: This condition will always return 'false' since the types 'keyof O' and '"c"' have no overlap.
3+
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(247,10): error TS2339: Property 'kind' does not exist on type 'never'.
34

45

5-
==== tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts (2 errors) ====
6+
==== tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts (3 errors) ====
67
function f1(x: 1 | 2): string {
78
if (!!true) {
89
switch (x) {
@@ -244,4 +245,17 @@ tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(235,5): error
244245
!!! error TS2367: This condition will always return 'false' since the types 'keyof O' and '"c"' have no overlap.
245246
return o[k];
246247
}
247-
248+
249+
// Repro from #35431
250+
type A = { kind: "abc" } | { kind: "def" };
251+
252+
function f35431(a: A) {
253+
switch (a.kind) {
254+
case "abc":
255+
case "def": return;
256+
default:
257+
a!.kind; // Error expected
258+
~~~~
259+
!!! error TS2339: Property 'kind' does not exist on type 'never'.
260+
}
261+
}

tests/baselines/reference/exhaustiveSwitchStatements1.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,18 @@ function ff(o: O, k: K) {
236236
k === 'c'; // Error
237237
return o[k];
238238
}
239-
239+
240+
// Repro from #35431
241+
type A = { kind: "abc" } | { kind: "def" };
242+
243+
function f35431(a: A) {
244+
switch (a.kind) {
245+
case "abc":
246+
case "def": return;
247+
default:
248+
a!.kind; // Error expected
249+
}
250+
}
240251

241252
//// [exhaustiveSwitchStatements1.js]
242253
"use strict";
@@ -453,6 +464,14 @@ function ff(o, k) {
453464
k === 'c'; // Error
454465
return o[k];
455466
}
467+
function f35431(a) {
468+
switch (a.kind) {
469+
case "abc":
470+
case "def": return;
471+
default:
472+
a.kind; // Error expected
473+
}
474+
}
456475

457476

458477
//// [exhaustiveSwitchStatements1.d.ts]
@@ -524,3 +543,9 @@ declare type O = {
524543
};
525544
declare type K = keyof O | 'c';
526545
declare function ff(o: O, k: K): number;
546+
declare type A = {
547+
kind: "abc";
548+
} | {
549+
kind: "def";
550+
};
551+
declare function f35431(a: A): void;

tests/baselines/reference/exhaustiveSwitchStatements1.symbols

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,3 +603,26 @@ function ff(o: O, k: K) {
603603
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
604604
}
605605

606+
// Repro from #35431
607+
type A = { kind: "abc" } | { kind: "def" };
608+
>A : Symbol(A, Decl(exhaustiveSwitchStatements1.ts, 236, 1))
609+
>kind : Symbol(kind, Decl(exhaustiveSwitchStatements1.ts, 239, 10))
610+
>kind : Symbol(kind, Decl(exhaustiveSwitchStatements1.ts, 239, 28))
611+
612+
function f35431(a: A) {
613+
>f35431 : Symbol(f35431, Decl(exhaustiveSwitchStatements1.ts, 239, 43))
614+
>a : Symbol(a, Decl(exhaustiveSwitchStatements1.ts, 241, 16))
615+
>A : Symbol(A, Decl(exhaustiveSwitchStatements1.ts, 236, 1))
616+
617+
switch (a.kind) {
618+
>a.kind : Symbol(kind, Decl(exhaustiveSwitchStatements1.ts, 239, 10), Decl(exhaustiveSwitchStatements1.ts, 239, 28))
619+
>a : Symbol(a, Decl(exhaustiveSwitchStatements1.ts, 241, 16))
620+
>kind : Symbol(kind, Decl(exhaustiveSwitchStatements1.ts, 239, 10), Decl(exhaustiveSwitchStatements1.ts, 239, 28))
621+
622+
case "abc":
623+
case "def": return;
624+
default:
625+
a!.kind; // Error expected
626+
>a : Symbol(a, Decl(exhaustiveSwitchStatements1.ts, 241, 16))
627+
}
628+
}

tests/baselines/reference/exhaustiveSwitchStatements1.types

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,3 +704,32 @@ function ff(o: O, k: K) {
704704
>k : keyof O
705705
}
706706

707+
// Repro from #35431
708+
type A = { kind: "abc" } | { kind: "def" };
709+
>A : A
710+
>kind : "abc"
711+
>kind : "def"
712+
713+
function f35431(a: A) {
714+
>f35431 : (a: A) => void
715+
>a : A
716+
717+
switch (a.kind) {
718+
>a.kind : "abc" | "def"
719+
>a : A
720+
>kind : "abc" | "def"
721+
722+
case "abc":
723+
>"abc" : "abc"
724+
725+
case "def": return;
726+
>"def" : "def"
727+
728+
default:
729+
a!.kind; // Error expected
730+
>a!.kind : any
731+
>a! : never
732+
>a : never
733+
>kind : any
734+
}
735+
}

tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,15 @@ function ff(o: O, k: K) {
239239
k === 'c'; // Error
240240
return o[k];
241241
}
242+
243+
// Repro from #35431
244+
type A = { kind: "abc" } | { kind: "def" };
245+
246+
function f35431(a: A) {
247+
switch (a.kind) {
248+
case "abc":
249+
case "def": return;
250+
default:
251+
a!.kind; // Error expected
252+
}
253+
}

0 commit comments

Comments
 (0)