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 10 lessons in each track are free. No card needed for those.