Skip to content

Bits of .NET

Daily micro-tips for C#, SQL, performance, and scalable backend engineering.

  • Asp.Net Core
  • C#
  • SQL
  • JavaScript
  • CSS
  • About
  • ErcanOPAK.com
  • No Access
  • Privacy Policy
JavaScript

JavaScript: Use Optional Chaining to Prevent ‘Cannot Read Property of Undefined’ Errors

- 03.02.26 - ErcanOPAK

Your app crashes with “Cannot read property ‘name’ of undefined”? Optional chaining (?.) safely accesses nested properties without try-catch blocks.

The Error-Prone Old Way:

const user = getUserData(); // Might return null

// ❌ This crashes if user is null/undefined
const name = user.profile.name;
// TypeError: Cannot read property 'profile' of undefined

// ❌ Traditional defensive code (ugly)
const name = user && user.profile && user.profile.name;

// ❌ Or with try-catch (expensive)
let name;
try {
    name = user.profile.name;
} catch (e) {
    name = 'Unknown';
}

The Modern Solution – Optional Chaining:

const user = getUserData();

// ✅ Safe access with ?.
const name = user?.profile?.name;

// If user is null/undefined → name = undefined
// If user.profile is null/undefined → name = undefined
// If user.profile.name exists → name = actual value

// No errors, no crashes!

How It Works:

// Short-circuits at first null/undefined
const result = obj?.prop1?.prop2?.prop3;

// Execution stops immediately if any part is null/undefined
// Think of it as:
if (obj === null || obj === undefined) {
    return undefined;
} else if (obj.prop1 === null || obj.prop1 === undefined) {
    return undefined;
} else if (obj.prop1.prop2 === null || obj.prop1.prop2 === undefined) {
    return undefined;
} else {
    return obj.prop1.prop2.prop3;
}

// But written in 1 clean line!

With Default Values:

// Combine with ?? (nullish coalescing)
const name = user?.profile?.name ?? 'Guest';

// If any part is null/undefined, use 'Guest'

// Difference from || operator:
const count = user?.stats?.count || 10;
// count = 10 if count is 0, false, '', etc. (BAD!)

const count = user?.stats?.count ?? 10;
// count = 10 ONLY if count is null/undefined (GOOD!)
// Preserves 0, false, ''

Array Access:

const users = getUsers(); // Might return null

// ❌ Crashes if users is null
const firstUser = users[0];

// ✅ Safe with ?.
const firstUser = users?.[0];

// ✅ Deep array access
const firstName = users?.[0]?.profile?.name;

Function Calls:

const api = getAPI(); // Might be undefined

// ❌ Crashes if api or api.getData is undefined
const data = api.getData();

// ✅ Safe optional call
const data = api?.getData?.();

// Only calls if both api exists AND getData is a function
// Returns undefined if either is missing

Real-World Example – API Response:

// API might return partial data or null
const response = await fetch('/api/user/123').then(r => r.json());

// ❌ Old way (prone to crashes)
const street = response.data.user.address.street;
const phone = response.data.user.contact.phone;

// ✅ New way (bulletproof)
const street = response?.data?.user?.address?.street ?? 'N/A';
const phone = response?.data?.user?.contact?.phone ?? 'No phone';

// Handles:
// - API returns null
// - User doesn't exist (data is null)
// - User has no address
// - Address has no street
// All gracefully without crashes!

Conditional Execution:

// Execute function only if it exists
onSuccess?.(); // Calls onSuccess() if it exists, does nothing if undefined

// Pass arguments
onUserLoad?.(userId, userData);

// Method chaining
user
    ?.getProfile?.()
    ?.updateName?.('John')
    ?.save?.();

// Each step executes only if previous step succeeded

Delete Operations:

// Safe delete
delete user?.profile?.tempData;

// Only deletes if user and profile exist
// No error if they don't

Limitations to Know:

// ❌ Can't use on left side of assignment
user?.name = 'John'; // SyntaxError!

// ✅ Check existence first
if (user) {
    user.name = 'John';
}

// ❌ Can't use with 'new'
const instance = new User?.(); // SyntaxError!

// ✅ Check constructor exists
const instance = User && new User();

Performance Considerations:

// Benchmark: 1 million accesses

// Traditional null checks
const result = obj && obj.a && obj.a.b && obj.a.b.c;
// Time: 125ms

// Optional chaining
const result = obj?.a?.b?.c;
// Time: 120ms

// Nearly identical performance!
// But much more readable

Browser Support:

Supported in:
✅ Chrome 80+ (2020)
✅ Firefox 74+ (2020)
✅ Safari 13.1+ (2020)
✅ Edge 80+ (2020)
✅ Node.js 14+

= 97% of users worldwide

For older browsers, Babel transpiles it:
obj?.a?.b  →  obj == null ? undefined : obj.a == null ? undefined : obj.a.b

Related posts:

AJAX “Stale Data” — Browser Caching GET Requests Deeply

JavaScript Web Workers — Real Multithreading for Heavy Tasks

AJAX Cache Nightmare — Why Your GET Requests Don’t Update

Post Views: 3

Post navigation

HTML5: Use Picture Element for Responsive Images (Better Than srcset)
AJAX: Use Axios Interceptors to Automatically Retry Failed Requests

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

February 2026
M T W T F S S
 1
2345678
9101112131415
16171819202122
232425262728  
« Jan    

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (935)
  • How to add default value for Entity Framework migrations for DateTime and Bool (831)
  • Get the First and Last Word from a String or Sentence in SQL (825)
  • How to select distinct rows in a datatable in C# (799)
  • How to make theater mode the default for Youtube (714)
  • Add Constraint to SQL Table to ensure email contains @ (573)
  • How to enable, disable and check if Service Broker is enabled on a database in SQL Server (552)
  • Average of all values in a column that are not zero in SQL (519)
  • How to use Map Mode for Vertical Scroll Mode in Visual Studio (474)
  • Find numbers with more than two decimal places in SQL (436)

Recent Posts

  • C#: Use ArgumentNullException.ThrowIfNull for Cleaner Validation
  • C#: Use Discard Pattern to Ignore Unwanted Values
  • C#: Use Deconstruction with Tuples for Cleaner Multiple Returns
  • C#: Use File-Scoped Types to Limit Class Visibility
  • SQL: Use PIVOT to Transform Rows into Columns
  • SQL: Use MERGE OUTPUT to Track What Changed During Upsert
  • .NET Core: Use Polly for Resilient HTTP Requests with Retry Logic
  • .NET Core: Use Dapper for Lightweight ORM Alternative to Entity Framework
  • Git: Use git sparse-checkout to Clone Only Specific Folders
  • Git: Use git switch and git restore Instead of Confusing git checkout

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (935)
  • How to add default value for Entity Framework migrations for DateTime and Bool (831)
  • Get the First and Last Word from a String or Sentence in SQL (825)
  • How to select distinct rows in a datatable in C# (799)
  • How to make theater mode the default for Youtube (714)

Recent Posts

  • C#: Use ArgumentNullException.ThrowIfNull for Cleaner Validation
  • C#: Use Discard Pattern to Ignore Unwanted Values
  • C#: Use Deconstruction with Tuples for Cleaner Multiple Returns
  • C#: Use File-Scoped Types to Limit Class Visibility
  • SQL: Use PIVOT to Transform Rows into Columns

Social

  • ErcanOPAK.com
  • GoodReads
  • LetterBoxD
  • Linkedin
  • The Blog
  • Twitter
© 2026 Bits of .NET | Built with Xblog Plus free WordPress theme by wpthemespace.com