Skip to content

Commit 403a93d

Browse files
Merge pull request #6330 from weswigham/restorative-narrowing
Fix #6277
2 parents 1868caa + 7bb2ee5 commit 403a93d

File tree

5 files changed

+192
-4
lines changed

5 files changed

+192
-4
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6722,10 +6722,6 @@ namespace ts {
67226722
if (typeInfo && typeInfo.type === undefinedType) {
67236723
return type;
67246724
}
6725-
// If the type to be narrowed is any and we're checking a primitive with assumeTrue=true, return the primitive
6726-
if (!!(type.flags & TypeFlags.Any) && typeInfo && assumeTrue) {
6727-
return typeInfo.type;
6728-
}
67296725
let flags: TypeFlags;
67306726
if (typeInfo) {
67316727
flags = typeInfo.flags;
@@ -6736,6 +6732,10 @@ namespace ts {
67366732
}
67376733
// At this point we can bail if it's not a union
67386734
if (!(type.flags & TypeFlags.Union)) {
6735+
// If we're on the true branch and the type is a subtype, we should return the primitive type
6736+
if (assumeTrue && typeInfo && isTypeSubtypeOf(typeInfo.type, type)) {
6737+
return typeInfo.type;
6738+
}
67396739
// If the active non-union type would be removed from a union by this type guard, return an empty union
67406740
return filterUnion(type) ? type : emptyUnionType;
67416741
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//// [typeGuardOfFormTypeOfPrimitiveSubtype.ts]
2+
let a: {};
3+
let b: {toString(): string};
4+
if (typeof a === "number") {
5+
let c: number = a;
6+
}
7+
if (typeof a === "string") {
8+
let c: string = a;
9+
}
10+
if (typeof a === "boolean") {
11+
let c: boolean = a;
12+
}
13+
14+
if (typeof b === "number") {
15+
let c: number = b;
16+
}
17+
if (typeof b === "string") {
18+
let c: string = b;
19+
}
20+
if (typeof b === "boolean") {
21+
let c: boolean = b;
22+
}
23+
24+
25+
//// [typeGuardOfFormTypeOfPrimitiveSubtype.js]
26+
var a;
27+
var b;
28+
if (typeof a === "number") {
29+
var c = a;
30+
}
31+
if (typeof a === "string") {
32+
var c = a;
33+
}
34+
if (typeof a === "boolean") {
35+
var c = a;
36+
}
37+
if (typeof b === "number") {
38+
var c = b;
39+
}
40+
if (typeof b === "string") {
41+
var c = b;
42+
}
43+
if (typeof b === "boolean") {
44+
var c = b;
45+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfPrimitiveSubtype.ts ===
2+
let a: {};
3+
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
4+
5+
let b: {toString(): string};
6+
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
7+
>toString : Symbol(toString, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 8))
8+
9+
if (typeof a === "number") {
10+
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
11+
12+
let c: number = a;
13+
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 3, 7))
14+
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
15+
}
16+
if (typeof a === "string") {
17+
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
18+
19+
let c: string = a;
20+
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 6, 7))
21+
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
22+
}
23+
if (typeof a === "boolean") {
24+
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
25+
26+
let c: boolean = a;
27+
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 9, 7))
28+
>a : Symbol(a, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 0, 3))
29+
}
30+
31+
if (typeof b === "number") {
32+
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
33+
34+
let c: number = b;
35+
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 13, 7))
36+
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
37+
}
38+
if (typeof b === "string") {
39+
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
40+
41+
let c: string = b;
42+
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 16, 7))
43+
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
44+
}
45+
if (typeof b === "boolean") {
46+
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
47+
48+
let c: boolean = b;
49+
>c : Symbol(c, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 19, 7))
50+
>b : Symbol(b, Decl(typeGuardOfFormTypeOfPrimitiveSubtype.ts, 1, 3))
51+
}
52+
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfPrimitiveSubtype.ts ===
2+
let a: {};
3+
>a : {}
4+
5+
let b: {toString(): string};
6+
>b : { toString(): string; }
7+
>toString : () => string
8+
9+
if (typeof a === "number") {
10+
>typeof a === "number" : boolean
11+
>typeof a : string
12+
>a : {}
13+
>"number" : string
14+
15+
let c: number = a;
16+
>c : number
17+
>a : number
18+
}
19+
if (typeof a === "string") {
20+
>typeof a === "string" : boolean
21+
>typeof a : string
22+
>a : {}
23+
>"string" : string
24+
25+
let c: string = a;
26+
>c : string
27+
>a : string
28+
}
29+
if (typeof a === "boolean") {
30+
>typeof a === "boolean" : boolean
31+
>typeof a : string
32+
>a : {}
33+
>"boolean" : string
34+
35+
let c: boolean = a;
36+
>c : boolean
37+
>a : boolean
38+
}
39+
40+
if (typeof b === "number") {
41+
>typeof b === "number" : boolean
42+
>typeof b : string
43+
>b : { toString(): string; }
44+
>"number" : string
45+
46+
let c: number = b;
47+
>c : number
48+
>b : number
49+
}
50+
if (typeof b === "string") {
51+
>typeof b === "string" : boolean
52+
>typeof b : string
53+
>b : { toString(): string; }
54+
>"string" : string
55+
56+
let c: string = b;
57+
>c : string
58+
>b : string
59+
}
60+
if (typeof b === "boolean") {
61+
>typeof b === "boolean" : boolean
62+
>typeof b : string
63+
>b : { toString(): string; }
64+
>"boolean" : string
65+
66+
let c: boolean = b;
67+
>c : boolean
68+
>b : boolean
69+
}
70+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
let a: {};
2+
let b: {toString(): string};
3+
if (typeof a === "number") {
4+
let c: number = a;
5+
}
6+
if (typeof a === "string") {
7+
let c: string = a;
8+
}
9+
if (typeof a === "boolean") {
10+
let c: boolean = a;
11+
}
12+
13+
if (typeof b === "number") {
14+
let c: number = b;
15+
}
16+
if (typeof b === "string") {
17+
let c: string = b;
18+
}
19+
if (typeof b === "boolean") {
20+
let c: boolean = b;
21+
}

0 commit comments

Comments
 (0)