Our code is more robust and legible. But we hide NULL under the rug
TL;DR: Avoid Nulls and undefined. If you avoid them you will never need Optionals.
Problems
Nulls
Solutions
Remove nulls
Deal with undefined
Context
Optional Chaining, Optionals, Coalescence, and many other solutions help us deal with the infamous nulls.
There's no need to use them once our code is mature, robust, and without nulls.
Sample Code
Wrong
const user = {
name: 'Hacker'
};
if (user?.credentials?.notExpired) {
user.login();
}
user.functionDefinedOrNot?.();
// Seems compact but it is hacky and has lots
// of potential NULLs and Undefined
Right
function login() {}
const user = {
name: 'Hacker',
credentials: { expired: false }
};
if (!user.credentials.expired) {
login();
}
// Also compact
// User is a real user or a polymorphic NullUser
// Credentials are always defined.
// Can be an instance of InvalidCredentials
// Assuming we eliminated nulls from our code
if (user.functionDefinedOrNot !== undefined) {
functionDefinedOrNot();
}
// This is also wrong.
// Explicit undefined checks are yet another code smell
Detection
[X] Automatic
This is a Language Feature.
We can detect it and remove it.
Tags
- Null
Conclusion
Many developers feel safe polluting the code with null dealing.
In fact, this is safes than not treating NULLs at all.
Nullish Values, Truthy and Falsy are also code smells.
We need to aim higher and make cleaner code.
The good: remove all nulls from your code
The bad: use optional chaining
The ugly: not treating nulls at all
Relations

Code Smell 145 - Short Circuit Hack
Maxi Contieri ・ Jun 30 '22

Code Smell 69 - Big Bang (JavaScript Ridiculous Castings)
Maxi Contieri ・ May 4 '21
More Info

Null: The Billion dollar mistake
Maxi Contieri ・ Nov 18 '20

How to Get Rid of Annoying IFs Forever
Maxi Contieri ・ Nov 9 '20
Credits
Photo by engin akyurt on Unsplash
He who fights with monsters might take care lest he thereby become a monster. And if you gaze for long into an abyss, the abyss gazes also into you.
Nietzsche

Software Engineering Great Quotes
Maxi Contieri ・ Dec 28 '20
This article is part of the CodeSmell Series.
Top comments (29)
This is your opinion, and is ok ... my problem is mainly that is presented as fact, when it isn't.
You say that it "seems compact", but it IS compact. You also say is "hacky", but...
Your proposed "solutions" are to either take more memory with default values (in the case of the object), or do an unnecessary checks that are already done for you with optional chaining (in the case of the function). You can see how TypeScript handles optional chaining when compiled as ES5 here, but the long story short is that is pretty much the same as what you did with the if, but with less boilerplate.
Now don't get me wrong, I agree with your point about how
null
should be avoided (I even wrote about that on a post of mine), butundefined
is ok, and both optional chaining and nullish coalescing are great tools to deal with possible missing values. Writing your own "abstraction" of nullish values serves no purpose other than over-engineering and over-complicating a simple language feature.One thing that we need to keep in mind as developers, is that stuff that looks like a "good practice" in a language, doesn't necessarily translate to a "good practice" in another language (and it could even be consider bad). Case in point is that Java is an OOP language with strong use of classes, which I already discussed several times here in DEV are terrible in JavaScript (and I would even say are terrible in general), because they provide a really poor form of encapsulation and reuse, compared with just using functions, modules and composition. So maybe from a class mindset it makes sense to avoid language features such as optional chaining, but it definitely doesn't make sense from a JavaScript point of view, when it actually helps you write less boilerplate to achieve the same goal.
Is almost like when those devs that need to put everything inside classes to the point where if they need to do an addition, they...
But long story short, I would recommend to change the wording of this kind of articles a little to make them look more like "opinion/suggestions", and less like "facts/rules", so we avoid confusing juniors that might think this are like "universal rules" when they aren't.
Cheers!
1 I have no strong evidence it takes more memory.
Memory is expendable. Readability and maintainability aren't
It seems we are dealing with 'Premature Optimization'.
I also think 'undefined' are yet another code smell.
I will also very happy if juniors stop using nulls since we are no longer in the 50s.
But I wil DO take your advice and add a disclaimer these articles are opinions and write it down
I am also reading your articles!
I'm a beginner and am using
null
andundefined
in my current project, and I'd love to hear why they are bad. 🤔For example we have an
Order
object, and it has a property calledfinishedAt
with typeDate
. What should I return if the order is not finished? I'm usingnull
in this case.if the order is not finished you shouldnt ask for the date. it makes no sense in real world
An exception should follow fail fast principle
An unfinished order is signified with
.finishedAt = undefined
. If you make this property throw an exception, you are violating:dev.to/mcsee/code-smell-73-excepti...
Hi @mrcaidev! You can just omit it. From TypeScript, that
Order
type would look something like this:So we say
finishedAt
is optional (is not always there), that means it can be eitherDate
orundefined
. Then when you get that from the front-end, you can check iffinishedAt
is present, instead of checking if isnull
.The best thing is that the response will also be smaller:
The property is only sent if it is set, if not, then its omitted :D
Cheers!
no. an unfinished order has an status unfinished or it is directly unfinished.
Asking for its data is an Exceptional case. Therefore is not an exception for Expected Case
What is your date of death?
How would you answer it?
undefined? null ? 1970-01-01 ?
No. you should say: 'You cannot ask me this. I am still alive!!'
Date of death is an optional property that isn't set unless the status is "dead". You don't throw exceptions for optional properties x.x
Ok. That's your opinion.
I am not going to change it
Maybe write another smell about "optional" properties
How do you represent optional data, then? Do you create new classes for every possible scenario? Like
User
andDeadUser
instead of just having a status property and some optional properties that you read depending on that status?My "opinion" is based on the fact that throwing when accessing an optional property produces a bad DX because now I need to try/catch everything, and also produces a bad UX if we forget about it.
Is really easy to type optional arguments, and IDEs will pick on that and give you feedback if you're trying to read a property that might not be there unless you check or use optional chaining. We can't say the same thing about code that throws. We don't know when something might throw, do we need to do smellier things like wrapping everything in try/catch, using naming conventions to know when someone might throw, etc.
Nowadays folks tend to avoid libraries that throw just because they are unnecessarily problematic, so why would we write code that throws ourselves?
It is not User responsibilty to know if its dead or Alive.
Not everything is an attribute
Code Smell 35 - State as Properties
Maxi Contieri ・ Nov 27 '20 ・ 1 min read
Optional Arguments are 'easy' and 'buggy'. so you type hint but you skip type hinting.
I would not use a library that throws an exception.. unless I am making a mistake
Oh yeah, we are definitely in different boats here. Having a class for the Order status and another class for the Order is definitely what I was talking about when I mentioned over-engineering. Might make sense if you're working with the limitations that classes have, but doesn't make any sense to do that in JavaScript. This is what I was talking about when I said that "bad practices" in one language don't translate to "bad practices" in another. From my PoV, having a class for the status of another class is bonkers (heck, having an external object for the state of another object doesn't make much sense).
Thank you for your advice! I was too particular about keeping a fixed structure of the response data, thinking it would benefit in the long run. Now I know what I should do!
Well, what about
number | null
cases? Let's say you're checking pizza price in an app and for an unknown reason, backend cannot find a value for the price and sendsnull
, how would we eliminatenull
in this case? What would backend then have to send to the frontend if not anull
? 0? :)Some folks asked something similar in my article (they even use a pizza example, which I find really funny). My answer is simple:
500
with an error, not a200
withnull
s to fill the blanks.From the TypeScript perspective, the type would look something like this, to represent the optional value:
Instead of something like this that's actually quite smelly:
Folks generally try to "defend"
null
as a "intentionally blank value" and compare it withundefined
as "unintentional left blank", but the reality is that nullish values are the same, and ideally you should be using just one, and I recommend usingundefined
because is the one the language uses.Maxi here in the article says that all nullish values are bad, but I don't agree.
undefined
is great for stuff that is actually "optional" (known asMaybe
in other languages, represented with?
in TypeScript). The alternative is to make it more complicated than it needs to be by adding default values, likenoop
s, empty objects, empty arrays, custom Nullish/Optional objects, and so on.What we both agree on, and if there is a single thing you take from this comment, is that if you see
null
in your code, that's a smell and almost certainly something that needs to be refactored.Cheers!
I see your point, but defining something as
undefined
explicitly when you need optional value does not look too attractive.Besides if you encounter a field which is undefined, there is no telling if it was intentionally set to
undefined
or was lost somewhere along the way. That'd make you check both for key and value presence to understand if the value is empty, unlike withnull
, which would require only one check, or with Maxi's default/empty value approach.The thing is, you don't need to make that distinction between "intentionally missing" or "unintentionally missing". You either have a value, or not. Tell me a scenario in which you think that distinction is useful, and I'll tell you how can that be handled without
null
(you don't need to take my word for it, there are others that think the same). The only check you make is withundefined
, which is true for both this scenarios:Both
foo
andbar
have to be deal with the same way, and can be checked with the same logic, so no need fornull
there either ^_^Lemme illustrate why the
undefined
doesn't look as a good alternative tonull
for me so far:in typescript returned type of
foo
will be inferred asvoid
(though the absence of value isundefined
), which means assigningvoid
toundefined
is a type error.What's worse is you can go ahead and write:
So
undefined
is assignable tovoid
andundefined
, butvoid
is not assignable toundefined
. But they are bothundefined
, that's even more confusing than havingnull
imo :)There's a few things to address here:
void
andundefined
aren't the same thing.void
is a type to signal developers that you shouldn't be using the return value of a function.undefined
is a value that you can use when the expected value is "missing" (for example, afind
function can returnundefined
when no item was found). So assigning the return value offoo
in this case to a constant is a mistake and is great to receive errors for that.foo
to something, then you have to be explicit about it:This is actually good, because you avoid returning
undefined
implicitly, you only returnundefined
as a value if that was what you wanted.foo
to something, that function would look something like:Both of the above return
string | undefined
, notstring | void
.null
, you end up writing almost the same code, but with the difference thatnull
has a lot of issues thatundefined
doesn't.undefined
implicitly in JavaScript, in TypeScript is inferred asvoid
, but that has nothing to do with differentiating between "intentionally" and "unintentionally" missing values.I'll give your approach a try and maybe come back with some arguments to your article :)
Hi
I am not saying undefined is better than null.
They are bad and introduce lots of IFs.
undefined is not a good alternative to null
We should avoid both
You mean number | number cases?
Nulls don't exist on real world
if backend cannot find a value it should an exception. Which is exactly what happen in real world
Backend should inform with exceptions. Nulls are schizofrenics. Exceptions are specific and handleable
I completly disagree here. Not about null being bad, but about exceptions as a replacement for null.
Null is not always conveying an error, you should take a step back when writing theses.
Null and undefined is often used for indicating optional values. Optional is not an error. And that is why a lot of language and libraries are supporting two kind of result types :
And you can declare both like this in typescript :
and
But those are not javascript native features, and then can have an impact on performance. If performance matters, using undefined and checking for it should be acceptable.
My own veteran opinion.
Hi Veteran
I am also a veteran and saw too many systems failing for the infamous null
The man who invented it regretted in public
Here is the whole story:
Null: The Billion dollar mistake
Maxi Contieri ・ Nov 18 '20 ・ 6 min read
And IMHO and experience. Performance (and premature optimization) are much less important than reliability and readability.
Performance was important on the 50s where nobody needed to maintain code.
I perfectly know about this. But you should also know that in javascript, null or undefined to not lead to the same kind of errors. Since this can't lead to undefined behaviour and arbitrary code execution that
C
has.Null or undefined in javascript lead to unchecked results and application
Panic
.Panics
are there to prevent exploits. So it will not lead to a CVE and an exploit unless you have a functionnal happy path that leads to an exploit. Which is not the same.To prevent the later, I recommend everyone to use Typescript and strictNullChecks by default to allow your static code analysis to detect these kind of defects.
In my opinion it's better than using runtime exceptions everywhere. Exceptions are hard to follow, they can't be statically analysed, they can lead to the same kind of issues if not checked, aka a system Panic.
"To prevent the later, I recommend everyone to use Typescript and strictNullChecks by default to allow your static code analysis to detect these kind of defects" awesome
And to clarify my point. That i think your article about
Null : The billion dollar mistake
misses to highlight.What was bad with NULL is design it in such a way that it can lead to undefined behaviour and arbitrary code execution. What was also bad was not adding a basic static analysis tools to detect when NULL is unchecked.
And to expand on what kind of issue unchecked NULL can lead to in javascript :
Panic
The main issue is with the first one. Since the second one will lead to a Fail Fast without any exploit possible.
So the first one is tricky, and is not just tied to NULL. Indeed, functionnal error (not handling all uses cases) can also be common on every langages, even those without NULL.
The solution to theses types of errors are nowadays to use a strict static analysis tools. And i repeat, these errors are not just tied to NULL.
Every modern langages now come with a static code analyzer embeded, I have given typescript example, but since i use a lot Rust langage, i can also say that it comes with one of the best static analysis tool out there (borrow checker, memory lifetime checking, etc are so wonderfull tools for static code analysis).
Imho work with user as class seems a little bit wierd. Behind of optional chaning usability is the outer data structure deep checking with sort code, I did not means as hack.