Reading Time: 5 minutes### Introduction
In the ever-evolving landscape of software development, engineers constantly seek ways to write cleaner, more efficient, and less error-prone code. One of the breakthrough features introduced in modern programming languages is optional chaining.
Optional chaining can be a game-changer, simplifying code and enhancing readability. If applied properly, it can also eliminate errors associated with null or undefined values. However, this comes as a double-edged sword, as it can also introduce risks that severely degrade the integrity of your code. We will go over the risks in a future section, but for now, let’s learn what Optional Chaining even is.
### What is Optional Chaining?
Optional chaining is a feature available in several modern languages, but I’ve seen it most in JavaScript and TypeScript. It is a way to decrease type errors by not assuming a given property will exist at all. In addition, it decreases errors thrown as a result of something being null or undefined.
However, this is a double-edged sword, as it can mask issues in stack traces or cause errors to throw too late, causing systematic issues that are larger than would otherwise exist.
The drawbacks of Optional Chaining make it a hotly debated topic among process steering engineers and code standards committees. I have been in a few calls and discussions that got quite heated due to optional chaining. Some call it an all-around risk, and others call for full adoption. There are inarguably safe ways to use Optional chaining, and we’ll discuss some in this next section.
### Using Optional Chaining
Here’s a basic example to illustrate optional chaining’s usage:
let user = {}; // user has no address
alert( user.address.street ); // (error)
alert( user?.address?.street ); // (no error)
No checks are made, and thus it throws an error in the first alert, as neither address nor street is defined under user. However, in the second alert, it would not throw an error, returning undefined instead. This is because the optional chaining broke at user?.address
, due to it being undefined.
This is quite powerful, as you can essentially skip any error relating to properties if they may be undefined. That is also why it is so dangerous, as sometimes you’ll need them to be defined. There are some ways to mitigate these issues, but at certain times you also have to ask whether it’s worth using optional chaining if you’ll need to write out more code just to check it, when not using it will have you writing the same checks.
Here’s a snippet from a project where I safely used optional chaining, reducing lines and not compromising safety:
// without optional chaining
const currentPage = () => {
if(router.pathname === '/') return 'Home'
const entry = Object.entries(PAGES).filter(filterFunc)
return entry[0][1].name;
//optional chaining
const currentPage = () => PAGES.find((page) => page.link === router.pathname)?.name || "Home"
There were a couple of other refactors that happened here, as entry[0][1].name
means that you’d have to understand the filterFunc
function to use it, and it likely isn’t designed in a human-friendly way, but ignoring that change, this function is much simpler with optional chaining than before. In addition, it only required one type check, and entirely rid itself of a secondary function full of other type checks.
These kinds of situations are where Optional chaining shines, and they aren’t super rare either. You just have to be wary that you fully understand the object you’re interacting with to ensure proper usage.
### Benefits of Optional Chaining
- Code Conciseness: Optional chaining reduces boilerplate code, making your codebase cleaner and more concise. It eliminates the need for repetitive null or undefined checks, resulting in more readable code.
- Error Prevention: By preventing runtime errors caused by null or undefined values, optional chaining helps improve the robustness and reliability of your applications. This is especially crucial in large codebases with multiple contributors.
- Improved Productivity: Developers can write code more efficiently and focus on solving the actual problems rather than handling null-related edge cases. This leads to increased productivity and faster development cycles.
- Better Code Maintenance: Code that relies on optional chaining is easier to maintain because it’s less error-prone and more self-explanatory. Future developers working on the codebase will appreciate the clarity it brings.
### Considerations and Best Practices
While optional chaining is a valuable tool, it’s essential to use it judiciously:
- Keep it readable: Don’t use syntax you find hard to read. Longer code is not always worse, and if it makes it more human-readable with no major slowdowns, it is better to keep it readable than to make it optimal.
- Avoid Overuse: Don’t blindly apply optional chaining everywhere. Use it when dealing with potentially nullable properties or methods to improve code readability and safety.
- Maintain Code Clarity: While optional chaining reduces code verbosity, it should not compromise code clarity. Name your variables and properties with meaning to ensure your code is human-readable.
### My Opinion
I’m of the mind that optional chaining is not a tool that should be used often. I understand there are clear benefits to it, such as not throwing errors for issues that won’t break anything, or to shorten syntax. I have used it before, so it isn’t something I am 100% against, however, I have found that in many cases you end up doing as many – if not more – type checks just to use optional chaining.
I also feel that most instances I’ve seen of it compromised the integrity of the code, didn’t shorten it, or made it less readable. While I don’t agree with the “don’t fix what ain’t broke” mentality a lot of the time, it is my personal opinion that type checking most of the time should not be fixed unless it is longer than necessary (as in there are two ifs that could be broken down further, or merged with past statements, etc.).
Of course, you should always know the data you’re working with and know what is safe to optionally chain and what isn’t, and any senior+ developers will already be using it safely. The above opinion mainly applies to people who haven’t learned about it yet, as they are also likely Junior engineers, and I’ve seen it become a very hard to correct bad habit when not used with enough discretion.
All I’m saying is to be very careful that you know your data. If you don’t, rather than resorting to optional chaining first, read your docs and learn what you’re unsure of, or reach out to someone else who’ll have the answer you need.
### Conclusion
Optional chaining is a simple yet powerful tool. As with most powerful tools in modern engineering, it comes with some large risks and must be used with discretion.
When in the hands of an experienced and thorough engineer, optional chaining can level up your code by a large margin, so don’t hesitate to add it if you’ve determined it’s the best option (had to add at least one bad pun). If you’re a junior engineer, you likely can use this tool to help you get a deeper grasp of the consideration that working with variable data requires.
As software development continues to evolve, mastering tools like optional chaining will become more essential for staying competitive and building robust applications. So regardless of your opinion on it, make sure you learn it and can use it safely.