Skip to content

Commit

Permalink
Cherry-pick PR #50553 into release-4.8 (#50589)
Browse files Browse the repository at this point in the history
Component commits:
3652682 {} & null and {} & undefined should be never in non-strictNullChecks mode

dd32cf8 Add tests

03cb73f Address code review feedback

4502553 Accept new baselines

Co-authored-by: Anders Hejlsberg <[email protected]>
  • Loading branch information
TypeScript Bot and ahejlsberg authored Sep 1, 2022
1 parent c9e06dc commit 502a908
Show file tree
Hide file tree
Showing 11 changed files with 347 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15134,7 +15134,7 @@ namespace ts {
return includes & TypeFlags.IncludesWildcard ? wildcardType : anyType;
}
if (!strictNullChecks && includes & TypeFlags.Nullable) {
return includes & TypeFlags.Undefined ? undefinedType : nullType;
return includes & TypeFlags.IncludesEmptyObject ? neverType : includes & TypeFlags.Undefined ? undefinedType : nullType;
}
if (includes & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ||
includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral ||
Expand Down
21 changes: 21 additions & 0 deletions tests/baselines/reference/NonNullableInNonStrictMode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//// [NonNullableInNonStrictMode.ts]
// These should all resolve to never

type T0 = NonNullable<null>;
type T1 = NonNullable<undefined>;
type T2 = null & {};
type T3 = undefined & {};
type T4 = null & undefined;
type T6 = null & { a: string } & {};

// Repro from #50519

type NonNullableNew<T> = T & {};
type NonNullableOld<T> = T extends null | undefined ? never : T;

type IsNullWithoutStrictNullChecks = NonNullableNew<null>;
type IsAlwaysNever = NonNullableOld<null>;


//// [NonNullableInNonStrictMode.js]
// These should all resolve to never
45 changes: 45 additions & 0 deletions tests/baselines/reference/NonNullableInNonStrictMode.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
=== tests/cases/compiler/NonNullableInNonStrictMode.ts ===
// These should all resolve to never

type T0 = NonNullable<null>;
>T0 : Symbol(T0, Decl(NonNullableInNonStrictMode.ts, 0, 0))
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))

type T1 = NonNullable<undefined>;
>T1 : Symbol(T1, Decl(NonNullableInNonStrictMode.ts, 2, 28))
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))

type T2 = null & {};
>T2 : Symbol(T2, Decl(NonNullableInNonStrictMode.ts, 3, 33))

type T3 = undefined & {};
>T3 : Symbol(T3, Decl(NonNullableInNonStrictMode.ts, 4, 20))

type T4 = null & undefined;
>T4 : Symbol(T4, Decl(NonNullableInNonStrictMode.ts, 5, 25))

type T6 = null & { a: string } & {};
>T6 : Symbol(T6, Decl(NonNullableInNonStrictMode.ts, 6, 27))
>a : Symbol(a, Decl(NonNullableInNonStrictMode.ts, 7, 18))

// Repro from #50519

type NonNullableNew<T> = T & {};
>NonNullableNew : Symbol(NonNullableNew, Decl(NonNullableInNonStrictMode.ts, 7, 36))
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 11, 20))
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 11, 20))

type NonNullableOld<T> = T extends null | undefined ? never : T;
>NonNullableOld : Symbol(NonNullableOld, Decl(NonNullableInNonStrictMode.ts, 11, 32))
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 12, 20))
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 12, 20))
>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 12, 20))

type IsNullWithoutStrictNullChecks = NonNullableNew<null>;
>IsNullWithoutStrictNullChecks : Symbol(IsNullWithoutStrictNullChecks, Decl(NonNullableInNonStrictMode.ts, 12, 64))
>NonNullableNew : Symbol(NonNullableNew, Decl(NonNullableInNonStrictMode.ts, 7, 36))

type IsAlwaysNever = NonNullableOld<null>;
>IsAlwaysNever : Symbol(IsAlwaysNever, Decl(NonNullableInNonStrictMode.ts, 14, 58))
>NonNullableOld : Symbol(NonNullableOld, Decl(NonNullableInNonStrictMode.ts, 11, 32))

43 changes: 43 additions & 0 deletions tests/baselines/reference/NonNullableInNonStrictMode.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
=== tests/cases/compiler/NonNullableInNonStrictMode.ts ===
// These should all resolve to never

type T0 = NonNullable<null>;
>T0 : never
>null : null

type T1 = NonNullable<undefined>;
>T1 : never

type T2 = null & {};
>T2 : never
>null : null

type T3 = undefined & {};
>T3 : never

type T4 = null & undefined;
>T4 : never
>null : null

type T6 = null & { a: string } & {};
>T6 : never
>null : null
>a : string

// Repro from #50519

type NonNullableNew<T> = T & {};
>NonNullableNew : NonNullableNew<T>

type NonNullableOld<T> = T extends null | undefined ? never : T;
>NonNullableOld : NonNullableOld<T>
>null : null

type IsNullWithoutStrictNullChecks = NonNullableNew<null>;
>IsNullWithoutStrictNullChecks : never
>null : null

type IsAlwaysNever = NonNullableOld<null>;
>IsAlwaysNever : never
>null : null

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//// [nonNullableAndObjectIntersections.ts]
// These should all resolve to never

type T0 = NonNullable<null>;
type T1 = NonNullable<undefined>;
type T2 = null & {};
type T3 = undefined & {};
type T4 = null & undefined;
type T6 = null & { a: string } & {};

// Repro from #50519

type NonNullableNew<T> = T & {};
type NonNullableOld<T> = T extends null | undefined ? never : T;

type TestNew = NonNullableNew<null>;
type TestOld = NonNullableOld<null>;


//// [nonNullableAndObjectIntersections.js]
// These should all resolve to never
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
=== tests/cases/compiler/nonNullableAndObjectIntersections.ts ===
// These should all resolve to never

type T0 = NonNullable<null>;
>T0 : Symbol(T0, Decl(nonNullableAndObjectIntersections.ts, 0, 0))
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))

type T1 = NonNullable<undefined>;
>T1 : Symbol(T1, Decl(nonNullableAndObjectIntersections.ts, 2, 28))
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))

type T2 = null & {};
>T2 : Symbol(T2, Decl(nonNullableAndObjectIntersections.ts, 3, 33))

type T3 = undefined & {};
>T3 : Symbol(T3, Decl(nonNullableAndObjectIntersections.ts, 4, 20))

type T4 = null & undefined;
>T4 : Symbol(T4, Decl(nonNullableAndObjectIntersections.ts, 5, 25))

type T6 = null & { a: string } & {};
>T6 : Symbol(T6, Decl(nonNullableAndObjectIntersections.ts, 6, 27))
>a : Symbol(a, Decl(nonNullableAndObjectIntersections.ts, 7, 18))

// Repro from #50519

type NonNullableNew<T> = T & {};
>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20))

type NonNullableOld<T> = T extends null | undefined ? never : T;
>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))

type TestNew = NonNullableNew<null>;
>TestNew : Symbol(TestNew, Decl(nonNullableAndObjectIntersections.ts, 12, 64))
>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36))

type TestOld = NonNullableOld<null>;
>TestOld : Symbol(TestOld, Decl(nonNullableAndObjectIntersections.ts, 14, 36))
>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32))

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
=== tests/cases/compiler/nonNullableAndObjectIntersections.ts ===
// These should all resolve to never

type T0 = NonNullable<null>;
>T0 : never
>null : null

type T1 = NonNullable<undefined>;
>T1 : never

type T2 = null & {};
>T2 : never
>null : null

type T3 = undefined & {};
>T3 : never

type T4 = null & undefined;
>T4 : never
>null : null

type T6 = null & { a: string } & {};
>T6 : never
>null : null
>a : string

// Repro from #50519

type NonNullableNew<T> = T & {};
>NonNullableNew : NonNullableNew<T>

type NonNullableOld<T> = T extends null | undefined ? never : T;
>NonNullableOld : NonNullableOld<T>
>null : null

type TestNew = NonNullableNew<null>;
>TestNew : never
>null : null

type TestOld = NonNullableOld<null>;
>TestOld : never
>null : null

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//// [nonNullableAndObjectIntersections.ts]
// These should all resolve to never

type T0 = NonNullable<null>;
type T1 = NonNullable<undefined>;
type T2 = null & {};
type T3 = undefined & {};
type T4 = null & undefined;
type T6 = null & { a: string } & {};

// Repro from #50519

type NonNullableNew<T> = T & {};
type NonNullableOld<T> = T extends null | undefined ? never : T;

type TestNew = NonNullableNew<null>;
type TestOld = NonNullableOld<null>;


//// [nonNullableAndObjectIntersections.js]
"use strict";
// These should all resolve to never
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
=== tests/cases/compiler/nonNullableAndObjectIntersections.ts ===
// These should all resolve to never

type T0 = NonNullable<null>;
>T0 : Symbol(T0, Decl(nonNullableAndObjectIntersections.ts, 0, 0))
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))

type T1 = NonNullable<undefined>;
>T1 : Symbol(T1, Decl(nonNullableAndObjectIntersections.ts, 2, 28))
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))

type T2 = null & {};
>T2 : Symbol(T2, Decl(nonNullableAndObjectIntersections.ts, 3, 33))

type T3 = undefined & {};
>T3 : Symbol(T3, Decl(nonNullableAndObjectIntersections.ts, 4, 20))

type T4 = null & undefined;
>T4 : Symbol(T4, Decl(nonNullableAndObjectIntersections.ts, 5, 25))

type T6 = null & { a: string } & {};
>T6 : Symbol(T6, Decl(nonNullableAndObjectIntersections.ts, 6, 27))
>a : Symbol(a, Decl(nonNullableAndObjectIntersections.ts, 7, 18))

// Repro from #50519

type NonNullableNew<T> = T & {};
>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20))

type NonNullableOld<T> = T extends null | undefined ? never : T;
>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))
>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20))

type TestNew = NonNullableNew<null>;
>TestNew : Symbol(TestNew, Decl(nonNullableAndObjectIntersections.ts, 12, 64))
>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36))

type TestOld = NonNullableOld<null>;
>TestOld : Symbol(TestOld, Decl(nonNullableAndObjectIntersections.ts, 14, 36))
>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32))

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
=== tests/cases/compiler/nonNullableAndObjectIntersections.ts ===
// These should all resolve to never

type T0 = NonNullable<null>;
>T0 : never
>null : null

type T1 = NonNullable<undefined>;
>T1 : never

type T2 = null & {};
>T2 : never
>null : null

type T3 = undefined & {};
>T3 : never

type T4 = null & undefined;
>T4 : never
>null : null

type T6 = null & { a: string } & {};
>T6 : never
>null : null
>a : string

// Repro from #50519

type NonNullableNew<T> = T & {};
>NonNullableNew : NonNullableNew<T>

type NonNullableOld<T> = T extends null | undefined ? never : T;
>NonNullableOld : NonNullableOld<T>
>null : null

type TestNew = NonNullableNew<null>;
>TestNew : never
>null : null

type TestOld = NonNullableOld<null>;
>TestOld : never
>null : null

18 changes: 18 additions & 0 deletions tests/cases/compiler/nonNullableAndObjectIntersections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @strict: true, false

// These should all resolve to never

type T0 = NonNullable<null>;
type T1 = NonNullable<undefined>;
type T2 = null & {};
type T3 = undefined & {};
type T4 = null & undefined;
type T6 = null & { a: string } & {};

// Repro from #50519

type NonNullableNew<T> = T & {};
type NonNullableOld<T> = T extends null | undefined ? never : T;

type TestNew = NonNullableNew<null>;
type TestOld = NonNullableOld<null>;

0 comments on commit 502a908

Please sign in to comment.