TypeScript

Lesson 04

Discriminated unions

Model related states with a discriminant so callers can narrow safely.

Good Code

result.ts
type SaveResult =
  | { status: "saved"; id: string }
  | { status: "failed"; message: string };

function renderSaveResult(result: SaveResult) {
  // The status field selects the only valid shape for each branch.
  if (result.status === "saved") {
    return "Saved draft " + result.id;
  }

  return "Could not save: " + result.message;
}

Bad Code

result.ts
type SaveResult = {
  saved?: boolean;
  id?: string;
  message?: string;
};

function renderSaveResult(result: SaveResult) {
  // Optional fields allow impossible combinations to compile.
  if (result.saved) {
    return "Saved draft " + result.id;
  }

  return "Could not save: " + result.message;
}

Review Notes

What to review

Good Code

The good version ties each shape to a clear status, so TypeScript can narrow the available fields in each branch.

Bad Code

The bad version leaves optional fields to be guessed together, allowing states like saved: true without an id or a failure without a message.

Takeaways

  • Use discriminated unions to make invalid states harder to express.