Skip to content

Commit 6db2c88

Browse files
authoredSep 1, 2022
{} & null and {} & undefined should always be never (#50553)
* {} & null and {} & undefined should be never in non-strictNullChecks mode * Add tests * Address code review feedback * Accept new baselines
1 parent 238c341 commit 6db2c88

11 files changed

+347
-1
lines changed
 

‎src/compiler/checker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15166,7 +15166,7 @@ namespace ts {
1516615166
return includes & TypeFlags.IncludesWildcard ? wildcardType : anyType;
1516715167
}
1516815168
if (!strictNullChecks && includes & TypeFlags.Nullable) {
15169-
return includes & TypeFlags.Undefined ? undefinedType : nullType;
15169+
return includes & TypeFlags.IncludesEmptyObject ? neverType : includes & TypeFlags.Undefined ? undefinedType : nullType;
1517015170
}
1517115171
if (includes & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ||
1517215172
includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral ||
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [NonNullableInNonStrictMode.ts]
2+
// These should all resolve to never
3+
4+
type T0 = NonNullable<null>;
5+
type T1 = NonNullable<undefined>;
6+
type T2 = null & {};
7+
type T3 = undefined & {};
8+
type T4 = null & undefined;
9+
type T6 = null & { a: string } & {};
10+
11+
// Repro from #50519
12+
13+
type NonNullableNew<T> = T & {};
14+
type NonNullableOld<T> = T extends null | undefined ? never : T;
15+
16+
type IsNullWithoutStrictNullChecks = NonNullableNew<null>;
17+
type IsAlwaysNever = NonNullableOld<null>;
18+
19+
20+
//// [NonNullableInNonStrictMode.js]
21+
// These should all resolve to never
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/NonNullableInNonStrictMode.ts ===
2+
// These should all resolve to never
3+
4+
type T0 = NonNullable<null>;
5+
>T0 : Symbol(T0, Decl(NonNullableInNonStrictMode.ts, 0, 0))
6+
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
7+
8+
type T1 = NonNullable<undefined>;
9+
>T1 : Symbol(T1, Decl(NonNullableInNonStrictMode.ts, 2, 28))
10+
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
11+
12+
type T2 = null & {};
13+
>T2 : Symbol(T2, Decl(NonNullableInNonStrictMode.ts, 3, 33))
14+
15+
type T3 = undefined & {};
16+
>T3 : Symbol(T3, Decl(NonNullableInNonStrictMode.ts, 4, 20))
17+
18+
type T4 = null & undefined;
19+
>T4 : Symbol(T4, Decl(NonNullableInNonStrictMode.ts, 5, 25))
20+
21+
type T6 = null & { a: string } & {};
22+
>T6 : Symbol(T6, Decl(NonNullableInNonStrictMode.ts, 6, 27))
23+
>a : Symbol(a, Decl(NonNullableInNonStrictMode.ts, 7, 18))
24+
25+
// Repro from #50519
26+
27+
type NonNullableNew<T> = T & {};
28+
>NonNullableNew : Symbol(NonNullableNew, Decl(NonNullableInNonStrictMode.ts, 7, 36))
29+
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 11, 20))
30+
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 11, 20))
31+
32+
type NonNullableOld<T> = T extends null | undefined ? never : T;
33+
>NonNullableOld : Symbol(NonNullableOld, Decl(NonNullableInNonStrictMode.ts, 11, 32))
34+
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 12, 20))
35+
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 12, 20))
36+
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 12, 20))
37+
38+
type IsNullWithoutStrictNullChecks = NonNullableNew<null>;
39+
>IsNullWithoutStrictNullChecks : Symbol(IsNullWithoutStrictNullChecks, Decl(NonNullableInNonStrictMode.ts, 12, 64))
40+
>NonNullableNew : Symbol(NonNullableNew, Decl(NonNullableInNonStrictMode.ts, 7, 36))
41+
42+
type IsAlwaysNever = NonNullableOld<null>;
43+
>IsAlwaysNever : Symbol(IsAlwaysNever, Decl(NonNullableInNonStrictMode.ts, 14, 58))
44+
>NonNullableOld : Symbol(NonNullableOld, Decl(NonNullableInNonStrictMode.ts, 11, 32))
45+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
=== tests/cases/compiler/NonNullableInNonStrictMode.ts ===
2+
// These should all resolve to never
3+
4+
type T0 = NonNullable<null>;
5+
>T0 : never
6+
>null : null
7+
8+
type T1 = NonNullable<undefined>;
9+
>T1 : never
10+
11+
type T2 = null & {};
12+
>T2 : never
13+
>null : null
14+
15+
type T3 = undefined & {};
16+
>T3 : never
17+
18+
type T4 = null & undefined;
19+
>T4 : never
20+
>null : null
21+
22+
type T6 = null & { a: string } & {};
23+
>T6 : never
24+
>null : null
25+
>a : string
26+
27+
// Repro from #50519
28+
29+
type NonNullableNew<T> = T & {};
30+
>NonNullableNew : NonNullableNew<T>
31+
32+
type NonNullableOld<T> = T extends null | undefined ? never : T;
33+
>NonNullableOld : NonNullableOld<T>
34+
>null : null
35+
36+
type IsNullWithoutStrictNullChecks = NonNullableNew<null>;
37+
>IsNullWithoutStrictNullChecks : never
38+
>null : null
39+
40+
type IsAlwaysNever = NonNullableOld<null>;
41+
>IsAlwaysNever : never
42+
>null : null
43+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [nonNullableAndObjectIntersections.ts]
2+
// These should all resolve to never
3+
4+
type T0 = NonNullable<null>;
5+
type T1 = NonNullable<undefined>;
6+
type T2 = null & {};
7+
type T3 = undefined & {};
8+
type T4 = null & undefined;
9+
type T6 = null & { a: string } & {};
10+
11+
// Repro from #50519
12+
13+
type NonNullableNew<T> = T & {};
14+
type NonNullableOld<T> = T extends null | undefined ? never : T;
15+
16+
type TestNew = NonNullableNew<null>;
17+
type TestOld = NonNullableOld<null>;
18+
19+
20+
//// [nonNullableAndObjectIntersections.js]
21+
// These should all resolve to never
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/nonNullableAndObjectIntersections.ts ===
2+
// These should all resolve to never
3+
4+
type T0 = NonNullable<null>;
5+
>T0 : Symbol(T0, Decl(nonNullableAndObjectIntersections.ts, 0, 0))
6+
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
7+
8+
type T1 = NonNullable<undefined>;
9+
>T1 : Symbol(T1, Decl(nonNullableAndObjectIntersections.ts, 2, 28))
10+
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
11+
12+
type T2 = null & {};
13+
>T2 : Symbol(T2, Decl(nonNullableAndObjectIntersections.ts, 3, 33))
14+
15+
type T3 = undefined & {};
16+
>T3 : Symbol(T3, Decl(nonNullableAndObjectIntersections.ts, 4, 20))
17+
18+
type T4 = null & undefined;
19+
>T4 : Symbol(T4, Decl(nonNullableAndObjectIntersections.ts, 5, 25))
20+
21+
type T6 = null & { a: string } & {};
22+
>T6 : Symbol(T6, Decl(nonNullableAndObjectIntersections.ts, 6, 27))
23+
>a : Symbol(a, Decl(nonNullableAndObjectIntersections.ts, 7, 18))
24+
25+
// Repro from #50519
26+
27+
type NonNullableNew<T> = T & {};
28+
>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36))
29+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20))
30+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20))
31+
32+
type NonNullableOld<T> = T extends null | undefined ? never : T;
33+
>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32))
34+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
35+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
36+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
37+
38+
type TestNew = NonNullableNew<null>;
39+
>TestNew : Symbol(TestNew, Decl(nonNullableAndObjectIntersections.ts, 12, 64))
40+
>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36))
41+
42+
type TestOld = NonNullableOld<null>;
43+
>TestOld : Symbol(TestOld, Decl(nonNullableAndObjectIntersections.ts, 14, 36))
44+
>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32))
45+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
=== tests/cases/compiler/nonNullableAndObjectIntersections.ts ===
2+
// These should all resolve to never
3+
4+
type T0 = NonNullable<null>;
5+
>T0 : never
6+
>null : null
7+
8+
type T1 = NonNullable<undefined>;
9+
>T1 : never
10+
11+
type T2 = null & {};
12+
>T2 : never
13+
>null : null
14+
15+
type T3 = undefined & {};
16+
>T3 : never
17+
18+
type T4 = null & undefined;
19+
>T4 : never
20+
>null : null
21+
22+
type T6 = null & { a: string } & {};
23+
>T6 : never
24+
>null : null
25+
>a : string
26+
27+
// Repro from #50519
28+
29+
type NonNullableNew<T> = T & {};
30+
>NonNullableNew : NonNullableNew<T>
31+
32+
type NonNullableOld<T> = T extends null | undefined ? never : T;
33+
>NonNullableOld : NonNullableOld<T>
34+
>null : null
35+
36+
type TestNew = NonNullableNew<null>;
37+
>TestNew : never
38+
>null : null
39+
40+
type TestOld = NonNullableOld<null>;
41+
>TestOld : never
42+
>null : null
43+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [nonNullableAndObjectIntersections.ts]
2+
// These should all resolve to never
3+
4+
type T0 = NonNullable<null>;
5+
type T1 = NonNullable<undefined>;
6+
type T2 = null & {};
7+
type T3 = undefined & {};
8+
type T4 = null & undefined;
9+
type T6 = null & { a: string } & {};
10+
11+
// Repro from #50519
12+
13+
type NonNullableNew<T> = T & {};
14+
type NonNullableOld<T> = T extends null | undefined ? never : T;
15+
16+
type TestNew = NonNullableNew<null>;
17+
type TestOld = NonNullableOld<null>;
18+
19+
20+
//// [nonNullableAndObjectIntersections.js]
21+
"use strict";
22+
// These should all resolve to never
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/nonNullableAndObjectIntersections.ts ===
2+
// These should all resolve to never
3+
4+
type T0 = NonNullable<null>;
5+
>T0 : Symbol(T0, Decl(nonNullableAndObjectIntersections.ts, 0, 0))
6+
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
7+
8+
type T1 = NonNullable<undefined>;
9+
>T1 : Symbol(T1, Decl(nonNullableAndObjectIntersections.ts, 2, 28))
10+
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
11+
12+
type T2 = null & {};
13+
>T2 : Symbol(T2, Decl(nonNullableAndObjectIntersections.ts, 3, 33))
14+
15+
type T3 = undefined & {};
16+
>T3 : Symbol(T3, Decl(nonNullableAndObjectIntersections.ts, 4, 20))
17+
18+
type T4 = null & undefined;
19+
>T4 : Symbol(T4, Decl(nonNullableAndObjectIntersections.ts, 5, 25))
20+
21+
type T6 = null & { a: string } & {};
22+
>T6 : Symbol(T6, Decl(nonNullableAndObjectIntersections.ts, 6, 27))
23+
>a : Symbol(a, Decl(nonNullableAndObjectIntersections.ts, 7, 18))
24+
25+
// Repro from #50519
26+
27+
type NonNullableNew<T> = T & {};
28+
>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36))
29+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20))
30+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20))
31+
32+
type NonNullableOld<T> = T extends null | undefined ? never : T;
33+
>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32))
34+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
35+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
36+
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
37+
38+
type TestNew = NonNullableNew<null>;
39+
>TestNew : Symbol(TestNew, Decl(nonNullableAndObjectIntersections.ts, 12, 64))
40+
>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36))
41+
42+
type TestOld = NonNullableOld<null>;
43+
>TestOld : Symbol(TestOld, Decl(nonNullableAndObjectIntersections.ts, 14, 36))
44+
>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32))
45+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
=== tests/cases/compiler/nonNullableAndObjectIntersections.ts ===
2+
// These should all resolve to never
3+
4+
type T0 = NonNullable<null>;
5+
>T0 : never
6+
>null : null
7+
8+
type T1 = NonNullable<undefined>;
9+
>T1 : never
10+
11+
type T2 = null & {};
12+
>T2 : never
13+
>null : null
14+
15+
type T3 = undefined & {};
16+
>T3 : never
17+
18+
type T4 = null & undefined;
19+
>T4 : never
20+
>null : null
21+
22+
type T6 = null & { a: string } & {};
23+
>T6 : never
24+
>null : null
25+
>a : string
26+
27+
// Repro from #50519
28+
29+
type NonNullableNew<T> = T & {};
30+
>NonNullableNew : NonNullableNew<T>
31+
32+
type NonNullableOld<T> = T extends null | undefined ? never : T;
33+
>NonNullableOld : NonNullableOld<T>
34+
>null : null
35+
36+
type TestNew = NonNullableNew<null>;
37+
>TestNew : never
38+
>null : null
39+
40+
type TestOld = NonNullableOld<null>;
41+
>TestOld : never
42+
>null : null
43+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @strict: true, false
2+
3+
// These should all resolve to never
4+
5+
type T0 = NonNullable<null>;
6+
type T1 = NonNullable<undefined>;
7+
type T2 = null & {};
8+
type T3 = undefined & {};
9+
type T4 = null & undefined;
10+
type T6 = null & { a: string } & {};
11+
12+
// Repro from #50519
13+
14+
type NonNullableNew<T> = T & {};
15+
type NonNullableOld<T> = T extends null | undefined ? never : T;
16+
17+
type TestNew = NonNullableNew<null>;
18+
type TestOld = NonNullableOld<null>;

0 commit comments

Comments
 (0)
Please sign in to comment.