Home > Net >  Why `type T1 = undefined & {}` is never in Typescript?
Why `type T1 = undefined & {}` is never in Typescript?

Time:09-30

I looked it up in the TypeScript document.

The docs says NonNullable excludes null or undefined

type NonNullable<T> = T & {};

Why undefined & {} is never?

https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype

CodePudding user response:

{} is a weird type in Typescript, which is why most style guides recommend against using it in your own code. Generally speaking, structural types enclosed in curly braces in Typescript are constraints placed upon non-null values. So { a: number } is the type of "anything in Typescript which is non-null-ish and has an a field of type number".

As a natural extension of this rule, {} is the type with no constraints, except for the non-null part. So {} is the type of all non-null-ish values in Typescript. It includes things like {} (obviously), other objects like { a: 1 } and { b: "Some string" }, but it also includes numbers and strings. The number 42 is a non-null-ish value which satisfies all of the (zero) properties we placed upon our type, so 42 is of type {}.

However, {} is still defined not to accept null or undefined, so {} & undefined must contain no values.

Note that this is all only true in --strictNullChecks. WIthout --strictNullChecks, null and undefined inhabit every type in Typescript, and {} & undefined is equivalent to simply undefined, a type which contains the two values undefined and null.

CodePudding user response:

If you have two types, A, and B, then the intersection type A & B corresponds to all values which are both A and B at the same time.

The empty object type {} corresponds to any object-like value that you can index into without getting a runtime error. So all object types are assignable to {}, as well as most primitive types like string (since strings have apparent properties like toUpperCase). The only values which are not assignable to {} are null and undefined. So you can think of {} as being "anything except null or undefined".

So, the type undefined & {} conceptually corresponds to all values which are both undefined and "anything except null or undefined". But there are no values that fit that, so, at least conceptually, undefined & {} is the empty intersection and should be equivalent to the impossible never type with no values.

In practice, sometimes TypeScript will not immediately reduce empty intersections to never. But any empty intersection involving at least one primitive type like undefined will indeed be so reduced, as implemented in microsoft/TypeScript#31838. So undefined & {} is never.


Note that the NonNullable<T> utility type has as of TypeScript 4.8 been redefined to be T & {}. Because {} is "everything except null or undefined", then conceptually an intersection of T with {} will produce a type like T with null and undefined removed from it.

From that point of view, NonNullable<undefined> or NonNullable<null> should be never, since you're removing something from itself and are left with nothing.

  • Related