null vs undefined? What to choose? What to use?
Tags: javascript, typescript, learning
Published: 2023-08-23 09:32:50

If you have experience with writing JavaScript, you might have a preference of using undefined in place of null, and even go to an extent of casting null values to undefined instead. If you were any wiser, you'd have known that null and undefined are not supposed to be interchangeable.

Of course, the caveat of choosing one over the other, and/or switching between them isn't much of a conversation starter as it rarely causes any head turning issues in production...rarely! I say this because I'm certain that the use of a wrong type has caused issues which were solved without being fully understood.

Okay let's look at specifics.

## null
`null` is a primitive value that represents the intentional absence of any object value. Probably the most common keyword across a lot of programming languages and with a common definition too. Other languages get fancy and use `nil` instead. I'm not quiet sure yet if that's also an exact equivalent to null, but it's worth checking out.

## undefined
`undefined` is a primitive value used when a variable has not been assigned a value. This is just a JavaScript thing. With JavaScript you can travel back in time to make a variable not assigned a value.

"_But black dynamite, assigning null to a variable does the same thing_" see that's where you'd be wrong. Here's an analogy for you. We can say null is like loading a webpage and just getting a blank screen, but undefined is a '404 not found' error.

The two keywords do have some common traits though. Ones that I can think from the top of my head is, they're both falsy values. This means that if you have a Boolean expression like `if (null || undefined)` you'll always get false from it.

## What to choose? What to use?

Let me get this out the way first. You shouldn't really have to choose. Your circumstances have to either choose for you or you make the choice depending on the solution for the problem you're solving. This is the answer to almost every 'vs' question in programming, but no one likes it as it ends arguments too early.

Speaking of circumstances choosing for you. In most cases, if not all, variables that hold data moving to/from the user to some data store, even via http requests, you must have at some point dealt with transforming it or the form of it to JSON. JSON is an open standard file format and data interchange format. 

When consuming APIs through some library or dealing with databases, notice how your favorite library hints to giving you either the data of some property or null? Why don't your orm or database connector thingie mabob give you back a property as undefined? Because at that point it would be extremely difficult to tell whether the property in the structure you're dealing with even exists. Getting `{"foo": null}` is better than `{}` because I know that 'foo' does exist in some other condition. When you get a chance, open a javascript console and run the following:
```javascript
JSON.stringify({
  foo: null
  bar: undefined
})
```

Typescript particularly makes these choices very loud, as when you're defining your types, you need to specify whether a property of an object or a variable can hold either null, undefined or some type.

Let's make a scenario to conclude this mini rant.

You're writing a form with your favorite framework, that when a user types, a request to update the data is made to the backend and your backend should only update the fields that have been changed. Let's also assume we're using RESTful apis to further pin down the scope. How does your frontend communicate this? Lets say the form is for user details and the fields are "name", "age", "height".

If the request payload from the client is
```json
{
  "age": 24,
  "height": null
}
```

The backend can interpret this payload as:
- Property 'age' exists and has number. Update age with provided integer
- Property 'name' is not defined. Do nothing
- Property 'height' is null. Clear its field in the data store.

How does the backend figure out that the property 'name' is not defined? Because it isn't.
That payload is equivalent to the following 
```javascript
const body = {
  age: 24,
  height: null,
  name: undefined
}
```
Where the inclusion of 'name' is redundant. Misuse of 'undefined' in such cases is a common place for bugs too. When this object is used to create URL search parameters, it will interpret the keyword 'undefined' as a string, which hopefully if your favorite http client omits undefined properties for you in requests, you're lucky, but some serialize it incorrectly.

I even resort to having a helper function to create query parameters from an object to avoid this
```javascript
function createUrlSearchParamsFor(payload) {
  const safePayload = payload ? JSON.parse(JSON.stringify(payload)) : payload
  return new URLSearchParams(safePayload);
}
```
When a javascript object is being serialized, all undefined properties are discarded, remember 'undefined' means a property is yet to be assigned a value. But null on the other hand is known by JSON as its a valid JSON data type

That's it. Hope you learned something.

If you spot any interesting bits or tweaks to be done on this post, let's discuss it here or reach out on twitter