The weird JavaScript type system - typeof and NaNs
Tags: javascript, typescript, node, webdev
Published: 2021-11-24 10:49:49

Heya, nice to see you again in another article, today's topic is kind off functional programming, I thought it my be nice to get back the basics and talk about types which is one of my favourite topics.

So why not have a series that's dedicated to the typesystem that JS has?

In this article I'll to go all beasty about types and why you should really care about types, so hold tight and let's go.

"Stop using double equal, tripe equal for the way", you often see this recommendation in some courses, blogs, and even books that favors the tripe equal `===` over the double equal `==` as they claim it's better in terms of handling corner cases. **HELL NO**

I won't argue that back in time I believed such claim and even spread it in some of my courses, articles. But meh, we all do silly things.

So, let's get right into our topic and understand why I am so that irritated of this claim

## What types does JS have?

Surely you know what types the language you use supports, but bare with me and let's revisit them swiftly.

- Primitives

  - String
  - Number
  - Undefined, NULL
  - Symbol
  - Boolean

- Object
  - object (The object notation or an instance of a class maybe)
  - Array
  - Function

All the primitive types are treated by javascript as non-reference values a.k.a they get stored on the stack not the heap (We'll have another article about that I promise).

And all the descendendants of the `Object` type are treated as `Referenceable` values, as they get stored on the `heap` and their reference is stored on the `stack`

## The typeof Operator

This operator is kinda special as it's the only operator in javascript that can access non-existing variables in any scope, let's see the following example.

### Undeclared

```js
console.log(typeof undeclared) // undefined
```

Apparently, the variable `undeclared` doesn't exist in any scope, yet the `typeof` can access it, but what distrubs me that it returns `undefined` :/

Well, it might seem reasonable, but IMHO, I like to think of `undefined` as a representation of no value, more like the absence of a value, and I might assume that you too think of it like that, more like a placeholder to an upcoming value, consider the following example.

```ts
class User {
  protected db: Database

  constructor(db: Database) {
    this.db = db
  }
}
```

You're expecting the variable db to be instance of some `Database` entity, maybe you're injecting it to your `User` model to handle incoming requests related to database persistency.

Apart from that, what is the value of `db` before you pass it any instance? Yup, it's `undefined`, you haven't setted a value for it yet, so the absence of a value is represented by the keyword `undefined`, hopefully that makes sense.

But if so, what's the problem with returning `undefined` using `typeof` operator for non-existing variable?

Well, I agree with [Kyle Simpson](https://github.com/getify) that this is some sort of confusion, using the same data type for two separate concepts is not accurate, JavaScript could've introduced new type called `undeclared` to indicate that some variable is not defined in any accessible scope.

Further, neither me nor Kyle thought of this mental models by ourselves nor did anyone has this mental model, actually the EcmaScript guidelines says so.

![EcmaScript description of the undefined type](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ac2j4ya766hvc0pgqwaw.png)

But meh, adding something like this may cause a lot of bugs to existing code basis, you never know if someone uses such code.

### Null is an object

```js
let v = null

console.log(typeof v) // object
```

One of the weirdest parts of JavasScript, that it treats the `null` as if it's an object.

Well, I think there are two mental models that justify this behavior.

- Null is a representation of an empty object
- Null is just equal to undefined and that's a JS bug

Well let's walk through each behaviour and I'll let you decide which one makes more sense.

#### Null is an empty object

Consider the following piece of code.

```js
let nullObject = Object.create(null)

console.log(nullObject)
```

The output of this code would be something like `[Object: null prototype] {}`, thus there are some opinions or thoughts that the `null` type in JS is treated as `object` because it can be used as a `prototype` to other objects a.k.a if you want to create functionless -if you will- object which has no prototypes, therefore, it has any built-in support from JS object functionalities.

```js
let nullObject = Object.create(null)
let anotherObject = {}

console.log(anotherObject.toString()) // [Object object]
console.log(nullObject.toString()) // Throws an error
```

And once again, I am not making this up, that's what the EcmaScript specs says about the null type

![ES specs description about null value and type](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mxs9ggt38so1l94w1htb.png)

#### Null is undefined

I think this way of thinking is based on the idea that `console.log(null == undefined)` returns `true` or maybe you're like me, shifting from another language (PHP in my case) to JavaScript, either way, I think those both mental models are incorrect in some sense.

The first one totally ignores the fact that `console.log(null === undefined)` returns `false` which makes them completely different, and the second one judges JavaScript by other languages'rules, which is more worse.

> If you're doing JavaScript, do it in JavaScript way - Panda's Law #2

Yet, there are some corner cases that I'd like to treat null and undefined as equal types: If it makes sense!!

If I can write more concise code using the fact that they're equal in abstract (We'll explain this later in the Equality section of this series), sure I'll do so.

### Arrays are objects

This one is quite easy I'd say, but let's walk through it.

```js
let ages = [20, 21, 26, 42]

console.log(typeof ages) // "object"
```

This one is completely reasonable, as I mentioned earlier, the V8 engine treats arrays and objects alike in some ways to reduce the duplications in memory allocation (I promise there will an article for that..)

Therefore, if you want to make sure that some variable is an array, you have to use the Array constructor

```js
let ages = [20, 21, 26, 42]

console.log(Array.isArray(ages)) // true
```

And I think the rest of the types are quite reasonable about, like `typeof function(){}` returns `"function"` and so on.

## The special type NaN

The #1 misunderstood type in JS, I think if IEEE was paid 1 dollar for everytime the NaN thought to be not a number they would've been #1 in Nasdaq..

Yeh the NaN is made to be though of as `Not a number` but meh, not the real meaning of not being a number!!

```js
console.log(typeof NaN) // number
```

Like c'mon! the `typeof` operator says it's a number :"

I'd blame IEEE for not calling it `NavN` which stands for `Not a valid number` or `NarN` which stands for `Not a representable number` because that's what NaNs are.

consider the following examples.

```js
console.log(Number('abc')) // NaN
console.log(Number({ x: 1, y: 2 })) // NaN
console.log(Number([1, 2, 3, 4])) // NaN
console.log(Number('5')) // 5
console.log(Number(true)) // 1
```

So NaNs actually are numbers, but special number that cannot be represented in a numeric form, and I'll refer back to why we're having this argument.

Now that's done with, I'll see you in the next part ^^

Have a nice drink and a wish you a very pleasing day, Cheerio 💜

![Farewell](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tnqdvczsh09t1lw8lxxx.png)

## Consider supporting/following me

- [Github](https://github.com/ahmedosama-st/)
- [Linkedin](https://www.linkedin.com/in/ahmed-osama-2004ab163/)
- [Youtube](https://www.youtube.com/c/SecTheater)
- [Website](https://ahmedosama-st.github.io/codefolio/)