When accessing properties of nested objects in TypeScript, you may find yourself writing code like hoge.fuga.piyo. However, if fuga is null or undefined, you will encounter a runtime error: ‘Cannot read properties of null (reading “piyo”).’
The solution to this problem is optional chaining (?.).
In this article, we will discuss how to use optional chaining, what happens behind the scenes, and whether it is really necessary.
What is an optional chain (?.)?
An optional chain is a feature that allows you to safely access a property when the reference may be null or undefined.
More details are provided in the official documentation.
.png?pattern=cross&md=0&fontSize=75px&textColor=%23ffffff&textStrongColor=%238340BB&overlay=https%3A%2F%2Fraw.githubusercontent.com%2Fyytypescript%2Fog-image%2Fmain%2Fpublic%2Fogp-overlay.svg)
What happens to JavaScript after compilation?
This convenient optional chain (?.) is convenient, but when it is compiled from TypeScript to JavaScript, what kind of code does it convert to?
Let’s check it out on TypeScript Playground.
▼ TypeScript
const a = {b: 1}
const c = a.b
const d = a?.b
▼Compiled JavaScript (ES5)
"use strict";
const a = { b: 1 };
const c = a.b;
const d = a === null || a === void 0 ? void 0 : a.b;
As you can see, the simple notation ? is converted into a slightly complex ternary operator a === null || a === void 0 ? void 0 : a.b; after compilation.
Is optional chaining really necessary?
Optional chaining is very convenient, but I believe that we should not rely on it too much.
This is because the greatest strength of TypeScript is its ability to ensure safety through static analysis using types.
Optional chaining is a safety net that prevents errors at runtime. However, if we can eliminate the possibility of null or undefined at compile time, that is even better. This reduces code volume and improves readability.
Optional chaining is useful in cases where external factors, such as API responses, inevitably make something optional. However, for internal application logic, defining stricter types often allows you to write more robust code without needing optional chaining.