Skip to main content
JavaScript & the browser·Module C5 · Lesson 7
TaskDefine @typedef Ok ({kind:"ok", value:number}), Err ({kind:"err", message:string}), Result = Ok | Err. Write describe(r): "got <value>" or "fail: <message>". Log describe({kind:"ok",value:42}), describe({kind:"err",message:"boom"}).

Discriminated unions in JSDoc

175 XP12 min
Theory

Two shapes, one name

API responses often have a tag field that decides the shape:

{ "kind": "ok",  "value": 42 }
{ "kind": "err", "message": "boom" }

This is a discriminated union: same union type, the kind field picks which branch you're in. In JSDoc you express it as two @typedefs plus a third that unions them:

/**
 * @typedef {Object} Ok
 * @property {"ok"} kind
 * @property {number} value
 */
/**
 * @typedef {Object} Err
 * @property {"err"} kind
 * @property {string} message
 */
/** @typedef {Ok | Err} Result */

How the editor narrows

When you check the discriminator, the editor narrows the type:

/** @param {Result} r */
function describe(r) {
  if (r.kind === "ok")  return "got " + r.value;     // r is Ok here
  if (r.kind === "err") return "fail: " + r.message; // r is Err here
}

Inside each branch, IntelliSense only suggests the fields valid for that shape — same as TypeScript discriminated unions.

The take-home

Tagged unions encode "API guarantees this OR that, never both" directly in the type. Cheap, robust, no compiler required.

🔒

Sign up to start coding

Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial — card required, cancel anytime.

Sign up — free trial →

First 15 lessons in each track are free. No card needed for those.

PreviousNext lesson →

Get one Python or web tip a day — by email

Short, hand-written, no spam. Unsubscribe in one click.