Handling Complex Nullish Values in TypeScript Edge Cases

Learn how to handle complex nullish values in TypeScript and avoid common pitfalls with edge cases in your code.

When working with TypeScript, handling null and undefined values correctly is crucial to avoid runtime errors. The nullish coalescing operator (??) is a helpful tool, but complex data structures or edge cases can lead to unexpected issues. In this article, we'll explore how to handle complex nullish values safely and effectively.

The nullish coalescing operator (??) returns the right-hand side operand when the left-hand side operand is either null or undefined. Unlike the logical OR operator (||), it does not treat false, 0, or empty strings as nullish. Here's an example:

typescript
const value = null ?? 'default';
console.log(value); // Output: 'default'

const value2 = 0 ?? 42;
console.log(value2); // Output: 0 (because 0 is NOT nullish)

While ?? works well with simple values, handling nested or complex objects with possible nullish properties can be tricky. Consider the following example where we have a deeply nested object that might have undefined or null properties:

typescript
interface UserProfile {
  name: string | null;
  settings?: {
    theme: string | null;
    notifications?: boolean | null;
  } | null;
}

const user: UserProfile = {
  name: null,
  settings: {
    theme: null,
    notifications: undefined
  }
};

Trying to assign default values using ?? might not cover all cases because sometimes you might want to provide a default for nested properties that could be undefined or null. Here's how you can safely handle this:

typescript
const userName = user.name ?? 'Anonymous';
const userTheme = user.settings?.theme ?? 'light';
const userNotifications = user.settings?.notifications ?? true;

console.log({ userName, userTheme, userNotifications });
// Output: { userName: 'Anonymous', userTheme: 'light', userNotifications: true }

Notice the use of optional chaining (?.) before the nullish coalescing operator (??). This safely prevents errors if properties like settings are null or undefined. Another common edge case is when the property exists but is intentionally set to null or false. The nullish coalescing operator correctly distinguishes these cases.

Here is a practical tip: avoid combining ?? and || in the same expression to prevent confusing results. For example:

typescript
const num = 0;
const result = num ?? 42 || 100;
console.log(result); // Output: 0, because '??' has lower precedence than '||', which can cause confusion

Instead, use parentheses to clarify precedence or avoid mixing these operators:

typescript
const resultCorrect = (num ?? 42) || 100;
console.log(resultCorrect); // Output: 100 because num is 0, so 0 ?? 42 === 0, then 0 || 100 === 100

To summarize, when handling complex nullish values in TypeScript: - Use ?? instead of || to treat false, 0, and '' as valid values. - Use optional chaining (?.) before ?? for nested properties. - Avoid mixing ?? and || without parentheses. - Explicitly handle null or undefined in your types for clarity. Handling these edge cases properly makes your code safer, cleaner, and easier to maintain.