Taming TypeScript

The TypeScript Tutorial for The Hater

Dealing with Reality: Optional Properties

Not all data is created equal

So far, we've defined object shapes where every property is required. But in the real world, data is often messy and incomplete. Some users have a middle name, others don't.

If we make every property mandatory, our types become inflexible. TypeScript gives us a clean way to handle this: the optional property modifier (?).

The ? Modifier for Properties

By adding a question mark ? before the colon in a property definition, you tell TypeScript that the property is allowed to be missing.

middleName?: string;

This now correctly models our data: a User must have a firstName and lastName, but middleName is optional.

Exercise 1: Make it Optional

  1. The Product type below requires a discountCode.
  2. The tShirt object doesn't have a discountCode, so TypeScript shows an error.
  3. Fix the Product type by making the discountCode property optional.
Interactive Editor
Loading...

The Catch: Safely Accessing Optional Properties

Making a property optional means its type is now a union with undefined (e.g., string | undefined). If you try to use it directly, you'll get an error because you might be calling a method on undefined.

// ❌ Error: 'product.discountCode' is possibly 'undefined'.
console.log(product.discountCode.toUpperCase());

You asked a brilliant question: "Why can't I just put a ? there too?"

You absolutely can. This is a modern JavaScript feature called Optional Chaining, and it's the perfect tool for this job.

Solution: The Optional Chaining Operator (?.)

The optional chaining operator ?. is a clean, short way to safely access properties of an object that might be null or undefined.

product.discountCode?.toUpperCase()

This single line means: "If product.discountCode exists, call .toUpperCase() on it. If it doesn't exist, just stop and evaluate the whole expression to undefined." It's a built-in if check.

Exercise 2: Use Optional Chaining

  1. The function getDiscount tries to access .toUpperCase() on product.discountCode, which causes an error.
  2. Fix the error by using the optional chaining operator ?. to safely access the property.
Interactive Editor
Loading...
Click to see the solution
export {};

type Product = {
  name: string;
  price: number;
  discountCode?: string; 
};

function getDiscount(product: Product) {
// ✅ Correct!
return product.discountCode?.toUpperCase();
}

While optional chaining is perfect for one-liners, you can still use a traditional if block if you need to handle the else case or perform more complex logic. Both are valid, but optional chaining is often cleaner.

// The 'if' block version
if (product.discountCode) {
  console.log(product.discountCode.toUpperCase());
} else {
  console.log("No discount today!");
}