Skip to content

Commit b4d382b

Browse files
authoredDec 2, 2022
Cherry-pick changes for narrowing to tagged literal types.
1 parent e7a02f4 commit b4d382b

File tree

6 files changed

+191
-1
lines changed

6 files changed

+191
-1
lines changed
 

‎src/compiler/checker.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -21630,7 +21630,10 @@ namespace ts {
2163021630
}
2163121631

2163221632
function isUnitLikeType(type: Type): boolean {
21633-
return isUnitType(getBaseConstraintOrType(type));
21633+
// Intersections that reduce to 'never' (e.g. 'T & null' where 'T extends {}') are not unit types.
21634+
const t = getBaseConstraintOrType(type);
21635+
// Scan intersections such that tagged literal types are considered unit types.
21636+
return t.flags & TypeFlags.Intersection ? some((t as IntersectionType).types, isUnitType) : isUnitType(t);
2163421637
}
2163521638

2163621639
function extractUnitType(type: Type) {

‎tests/baselines/reference/unknownControlFlow.errors.txt

+22
Original file line numberDiff line numberDiff line change
@@ -444,4 +444,26 @@ tests/cases/conformance/types/unknown/unknownControlFlow.ts(293,5): error TS2345
444444
function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
445445
let r2: never = y as T_AB & undefined;
446446
}
447+
448+
// Repro from #51538
449+
450+
type Left = 'left';
451+
type Right = 'right' & { right: 'right' };
452+
type Either = Left | Right;
453+
454+
function assertNever(v: never): never {
455+
throw new Error('never');
456+
}
457+
458+
function fx20(value: Either) {
459+
if (value === 'left') {
460+
const foo: 'left' = value;
461+
}
462+
else if (value === 'right') {
463+
const bar: 'right' = value;
464+
}
465+
else {
466+
assertNever(value);
467+
}
468+
}
447469

‎tests/baselines/reference/unknownControlFlow.js

+43
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,28 @@ type AB = "A" | "B";
427427
function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
428428
let r2: never = y as T_AB & undefined;
429429
}
430+
431+
// Repro from #51538
432+
433+
type Left = 'left';
434+
type Right = 'right' & { right: 'right' };
435+
type Either = Left | Right;
436+
437+
function assertNever(v: never): never {
438+
throw new Error('never');
439+
}
440+
441+
function fx20(value: Either) {
442+
if (value === 'left') {
443+
const foo: 'left' = value;
444+
}
445+
else if (value === 'right') {
446+
const bar: 'right' = value;
447+
}
448+
else {
449+
assertNever(value);
450+
}
451+
}
430452

431453

432454
//// [unknownControlFlow.js]
@@ -772,6 +794,20 @@ function doSomething2(value) {
772794
function x(x, y) {
773795
var r2 = y;
774796
}
797+
function assertNever(v) {
798+
throw new Error('never');
799+
}
800+
function fx20(value) {
801+
if (value === 'left') {
802+
var foo_1 = value;
803+
}
804+
else if (value === 'right') {
805+
var bar = value;
806+
}
807+
else {
808+
assertNever(value);
809+
}
810+
}
775811

776812

777813
//// [unknownControlFlow.d.ts]
@@ -844,3 +880,10 @@ type R<T extends keyof TypeA> = T extends keyof TypeB ? [TypeA[T], TypeB[T]] : n
844880
type R2<T extends PropertyKey> = T extends keyof TypeA ? T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never : never;
845881
type AB = "A" | "B";
846882
declare function x<T_AB extends AB>(x: T_AB & undefined, y: any): void;
883+
type Left = 'left';
884+
type Right = 'right' & {
885+
right: 'right';
886+
};
887+
type Either = Left | Right;
888+
declare function assertNever(v: never): never;
889+
declare function fx20(value: Either): void;

‎tests/baselines/reference/unknownControlFlow.symbols

+48
Original file line numberDiff line numberDiff line change
@@ -995,3 +995,51 @@ function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
995995
>T_AB : Symbol(T_AB, Decl(unknownControlFlow.ts, 425, 11))
996996
}
997997

998+
// Repro from #51538
999+
1000+
type Left = 'left';
1001+
>Left : Symbol(Left, Decl(unknownControlFlow.ts, 427, 1))
1002+
1003+
type Right = 'right' & { right: 'right' };
1004+
>Right : Symbol(Right, Decl(unknownControlFlow.ts, 431, 19))
1005+
>right : Symbol(right, Decl(unknownControlFlow.ts, 432, 24))
1006+
1007+
type Either = Left | Right;
1008+
>Either : Symbol(Either, Decl(unknownControlFlow.ts, 432, 42))
1009+
>Left : Symbol(Left, Decl(unknownControlFlow.ts, 427, 1))
1010+
>Right : Symbol(Right, Decl(unknownControlFlow.ts, 431, 19))
1011+
1012+
function assertNever(v: never): never {
1013+
>assertNever : Symbol(assertNever, Decl(unknownControlFlow.ts, 433, 27))
1014+
>v : Symbol(v, Decl(unknownControlFlow.ts, 435, 21))
1015+
1016+
throw new Error('never');
1017+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
1018+
}
1019+
1020+
function fx20(value: Either) {
1021+
>fx20 : Symbol(fx20, Decl(unknownControlFlow.ts, 437, 1))
1022+
>value : Symbol(value, Decl(unknownControlFlow.ts, 439, 14))
1023+
>Either : Symbol(Either, Decl(unknownControlFlow.ts, 432, 42))
1024+
1025+
if (value === 'left') {
1026+
>value : Symbol(value, Decl(unknownControlFlow.ts, 439, 14))
1027+
1028+
const foo: 'left' = value;
1029+
>foo : Symbol(foo, Decl(unknownControlFlow.ts, 441, 13))
1030+
>value : Symbol(value, Decl(unknownControlFlow.ts, 439, 14))
1031+
}
1032+
else if (value === 'right') {
1033+
>value : Symbol(value, Decl(unknownControlFlow.ts, 439, 14))
1034+
1035+
const bar: 'right' = value;
1036+
>bar : Symbol(bar, Decl(unknownControlFlow.ts, 444, 13))
1037+
>value : Symbol(value, Decl(unknownControlFlow.ts, 439, 14))
1038+
}
1039+
else {
1040+
assertNever(value);
1041+
>assertNever : Symbol(assertNever, Decl(unknownControlFlow.ts, 433, 27))
1042+
>value : Symbol(value, Decl(unknownControlFlow.ts, 439, 14))
1043+
}
1044+
}
1045+

‎tests/baselines/reference/unknownControlFlow.types

+52
Original file line numberDiff line numberDiff line change
@@ -1076,3 +1076,55 @@ function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
10761076
>y : any
10771077
}
10781078

1079+
// Repro from #51538
1080+
1081+
type Left = 'left';
1082+
>Left : "left"
1083+
1084+
type Right = 'right' & { right: 'right' };
1085+
>Right : "right" & { right: 'right'; }
1086+
>right : "right"
1087+
1088+
type Either = Left | Right;
1089+
>Either : Right | "left"
1090+
1091+
function assertNever(v: never): never {
1092+
>assertNever : (v: never) => never
1093+
>v : never
1094+
1095+
throw new Error('never');
1096+
>new Error('never') : Error
1097+
>Error : ErrorConstructor
1098+
>'never' : "never"
1099+
}
1100+
1101+
function fx20(value: Either) {
1102+
>fx20 : (value: Either) => void
1103+
>value : Either
1104+
1105+
if (value === 'left') {
1106+
>value === 'left' : boolean
1107+
>value : Either
1108+
>'left' : "left"
1109+
1110+
const foo: 'left' = value;
1111+
>foo : "left"
1112+
>value : "left"
1113+
}
1114+
else if (value === 'right') {
1115+
>value === 'right' : boolean
1116+
>value : Right
1117+
>'right' : "right"
1118+
1119+
const bar: 'right' = value;
1120+
>bar : "right"
1121+
>value : Right
1122+
}
1123+
else {
1124+
assertNever(value);
1125+
>assertNever(value) : never
1126+
>assertNever : (v: never) => never
1127+
>value : never
1128+
}
1129+
}
1130+

‎tests/cases/conformance/types/unknown/unknownControlFlow.ts

+22
Original file line numberDiff line numberDiff line change
@@ -429,3 +429,25 @@ type AB = "A" | "B";
429429
function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
430430
let r2: never = y as T_AB & undefined;
431431
}
432+
433+
// Repro from #51538
434+
435+
type Left = 'left';
436+
type Right = 'right' & { right: 'right' };
437+
type Either = Left | Right;
438+
439+
function assertNever(v: never): never {
440+
throw new Error('never');
441+
}
442+
443+
function fx20(value: Either) {
444+
if (value === 'left') {
445+
const foo: 'left' = value;
446+
}
447+
else if (value === 'right') {
448+
const bar: 'right' = value;
449+
}
450+
else {
451+
assertNever(value);
452+
}
453+
}

0 commit comments

Comments
 (0)
Please sign in to comment.