1

I was experimenting with some intersection between common primitive types in Typescript.

strictNullChecks

By default null and undefined are subtypes of all other types. That means you can assign null and undefined to something like number.

However, when using the --strictNullChecks flag, null and undefined are only assignable to unknown, any and their respective types (the one exception being that undefined is also assignable to void). This helps avoid many common errors. In cases where you want to pass in either a string or null or undefined, you can use the union type string | null | undefined.

Here are the tests I've run:

Typescript playground

// --strictNullChecks DISABLED

type BOOLEAN_STRING    = boolean & string;    // NEVER  
type BOOLEAN_NUMBER    = boolean & number;    // NEVER  
type BOOLEAN_UNDEFINED = boolean & undefined; // UNDEFINED
type BOOLEAN_NULL      = boolean & null;      // NULL

type STRING_NUMBER     = string & number;     // string & number  

type STRING_UNDEFINED  = string & undefined;  // UNDEFINED
type STRING_NULL       = string & null;       // NULL

type NUMBER_UNDEFINED  = number & undefined;  // UNDEFINED
type NUMBER_NULL       = number & null;       // NULL

Given the fact that null and undefined are subtypes of all other types (when --strictNullChecks is disabled), I guess all results make sense, except for one:

type STRING_NUMBER = string & number;     // string & number 

Shouldn't string & number be never?


I also ran the test with --strictNullChecks enabled.

Typescript playground

// --strictNullChecks ENABLED

type BOOLEAN_STRING    = boolean & string;    // NEVER  
type BOOLEAN_NUMBER    = boolean & number;    // NEVER  
type BOOLEAN_UNDEFINED = boolean & undefined; // NEVER
type BOOLEAN_NULL      = boolean & null;      // NEVER

type STRING_NUMBER     = string & number;    // string & number  

type STRING_UNDEFINED  = string & undefined; // string & undefined
type STRING_NULL       = string & null;      // string & null

type NUMBER_UNDEFINED  = number & undefined; // number & undefined
type NUMBER_NULL       = number & null;      // number & null

Given the fact that with strictNullChecks undefined and null are only assignable to unknown and any, shouldn't all the following be evaluated as never, instead of the intersection?

type STRING_UNDEFINED  = string & undefined; // string & undefined
type STRING_NULL       = string & null;      // string & null

type NUMBER_UNDEFINED  = number & undefined; // number & undefined
type NUMBER_NULL       = number & null;      // number & null
cbdeveloper
  • 27,898
  • 37
  • 155
  • 336
  • I think it's because of TS algorithms. Even if you see as a tooltip some intersection instead of ```never```, the behavior doesn't differ from ```never```. For example, you can't assign for variable typed as ```string & undefined``` neither ```string``` nor ```undefined``` when ```strictNullChecks``` enabled. – Николай Гольцев Dec 05 '20 at 11:56
  • @НиколайГольцев Yes, I've though that this could be a possibility. But take a look at this [answer](https://stackoverflow.com/a/52681859/10128619). He seems to use `string & number` in a way that is not `never`. What do you think? – cbdeveloper Dec 05 '20 at 11:59
  • If you try the code written in this answer and replace ```as string & number``` with ```as never``` you wouldn't see any difference. That's because ```never``` type is a subtype of any other type. This is some kind of proof that ```string & number``` always resolves to ```never``` even if TS shows in tooltip something different. Of course, maybe I'm wrong :) – Николай Гольцев Dec 05 '20 at 14:46
  • 2
    Also, if you switch to the latest version of TS in the playground then you'll see expected types :) – Николай Гольцев Dec 05 '20 at 14:57
  • You are right. Feel free to write an answer if you'd like. Thanks. – cbdeveloper Dec 06 '20 at 07:38

0 Answers0