Skip to main content
website logo savvydev
TypeScript Tip: Stop Writing Defensive Code with Optional Chaining

TypeScript Tip: Stop Writing Defensive Code with Optional Chaining

Learn how optional chaining can eliminate verbose null checks and make your React code cleaner. Perfect for social media sharing with interactive examples.

TypeScript React JavaScript Code Tip Optional Chaining

Ever find yourself writing defensive code like this? 🤔

// ❌ Verbose and repetitive
const userName =
  user && user.profile && user.profile.name ? user.profile.name : "Anonymous";
const userEmail =
  user && user.profile && user.profile.email ? user.profile.email : "";
const userAvatar =
  user && user.profile && user.profile.avatar
    ? user.profile.avatar
    : "/default-avatar.png";

Optional chaining (?.) is your friend! Here’s the clean way:

// ✅ Clean and readable
const userName = user?.profile?.name ?? "Anonymous";
const userEmail = user?.profile?.email ?? "";
const userAvatar = user?.profile?.avatar ?? "/default-avatar.png";

Why This Matters

  • Less code = fewer bugs
  • More readable = easier to maintain
  • Type-safe = TypeScript knows what’s happening
  • Performance = short-circuits on first falsy value

Real React Example

interface User {
  id: string;
  profile?: {
    name?: string;
    email?: string;
    avatar?: string;
  };
  settings?: {
    theme?: 'light' | 'dark';
    notifications?: boolean;
  };
}

function UserCard({ user }: { user?: User }) {
  return (
    <div className="user-card">
      <img
        src={user?.profile?.avatar ?? '/default-avatar.png'}
        alt={user?.profile?.name ?? 'User'}
      />
      <h3>{user?.profile?.name ?? 'Anonymous User'}</h3>
      <p>{user?.profile?.email ?? 'No email provided'}</p>
      <span className={`theme-${user?.settings?.theme ?? 'light'}`}>
        {user?.settings?.notifications ? '🔔' : '🔕'}
      </span>
    </div>
  );
}

Try It Yourself

Copy this code into your TypeScript playground and experiment:

interface User {
  id: string;
  profile?: {
    name?: string;
    email?: string;
    avatar?: string;
  };
  settings?: {
    theme?: "light" | "dark";
    notifications?: boolean;
  };
}

// Test data - try changing these values!
const user1: User = {
  id: "1",
  profile: {
    name: "Tony Sauvageau",
    email: "tony@example.com",
    avatar: "/tony-avatar.jpg",
  },
  settings: {
    theme: "dark",
    notifications: true,
  },
};

const user2: User = {
  id: "2",
  // Missing profile and settings!
};

const user3: User | undefined = undefined;

// Your code here - try different approaches!
function getUserInfo(user?: User) {
  // ❌ Old way (verbose)
  // const name = user && user.profile && user.profile.name ? user.profile.name : 'Anonymous';

  // ✅ New way (clean)
  const name = user?.profile?.name ?? "Anonymous";
  const email = user?.profile?.email ?? "No email";
  const theme = user?.settings?.theme ?? "light";

  return { name, email, theme };
}

// Test the function
console.log("User 1:", getUserInfo(user1));
console.log("User 2:", getUserInfo(user2));
console.log("User 3:", getUserInfo(user3));

Try these experiments:

  • Change the user data and see how optional chaining handles missing properties
  • Replace ?? with || and see the difference with falsy values
  • Add more nested optional properties and chain them

Pro Tips

  1. Combine with nullish coalescing (??) for better defaults
  2. Works with arrays too: users?.[0]?.name
  3. Function calls: user?.getFullName?.()
  4. TypeScript knows the types - no more any needed!

When NOT to Use

// ❌ Don't use when you expect the value to exist
const userId = user?.id; // If user exists, id should exist

// ✅ Better - let it fail fast
const userId = user.id;

The Bottom Line

Optional chaining eliminates defensive programming boilerplate. Your code becomes more readable, maintainable, and less prone to errors.

Pro tip: Combine with TypeScript’s strict null checks for maximum safety! 🚀


Want more TypeScript tips? Check out my TypeScript Patterns for React article for advanced patterns that separate junior from senior developers.