Handling Unexpected Null and Undefined Values in TypeScript Edge Cases

Learn how to effectively handle unexpected null and undefined values in TypeScript, avoiding common errors in your code with practical examples.

TypeScript helps catch many issues at compile time, but sometimes you might still encounter unexpected null or undefined values at runtime. This usually happens in edge cases when data is not as expected or external APIs return missing information. Handling these safely is key to preventing your app from crashing.

In this article, we'll explore simple ways to handle unexpected null and undefined values in TypeScript. We'll cover optional chaining, nullish coalescing, type narrowing, and explicit checks — all designed to keep your code safe and readable.

### 1. Optional Chaining (?.) Optional chaining lets you safely access deeply nested object properties without running into errors if something in the chain is null or undefined.

typescript
interface User {
  name: string;
  address?: {
    street?: string;
    city?: string;
  } | null;
}

const user: User = {
  name: "Alice",
  address: null,
};

// Without optional chaining, this causes an error if address is null or undefined
// const city = user.address.city; // Error: Object is possibly 'null'.

// Using optional chaining safely returns undefined if address or city is missing
const city = user.address?.city;
console.log(city); // Output: undefined

### 2. Nullish Coalescing (??) Use nullish coalescing to provide a default value when the left operand is null or undefined. This is helpful for fallback values.

typescript
const input: string | null = null;

// Without nullish coalescing
// const value = input || "default"; // This also treats empty string or 0 as false

// With nullish coalescing, only null or undefined triggers fallback
const value = input ?? "default";
console.log(value); // Output: "default"

### 3. Type Narrowing with if Checks Explicitly check for null or undefined before using a variable to narrow its type safely.

typescript
function printLength(str: string | null | undefined) {
  if (str == null) { // checks for both null and undefined
    console.log("No string provided");
  } else {
    console.log(`String length: ${str.length}`);
  }
}

printLength(null); // Output: No string provided
printLength("Hello"); // Output: String length: 5

### 4. Using Non-Null Assertion Operator (!) with Caution You can use the ! operator to tell TypeScript that a value is not null or undefined, but this can cause runtime errors if you're wrong. Use it only when you are certain.

typescript
const maybeValue: string | undefined = getValueFromSomewhere();

// TypeScript won't complain here, but you can get runtime error if maybeValue is undefined
const length = maybeValue!.length;

// Safer approach is to check before using ! or handle undefined properly

### Summary - Use optional chaining (?.) to safely access nested properties. - Use nullish coalescing (??) to provide default values when variables are null or undefined. - Use explicit checks (== null) to narrow variable types before use. - Avoid overusing non-null assertions (!) unless you are sure the value isn't null or undefined. Handling unexpected null and undefined values gracefully makes your TypeScript code more robust and easier to maintain. Keep these patterns in mind to avoid common runtime errors!