• Build a typed variant-constructor record plus closed Msg union from a record of tag → payload? declarations. The same record shape pairs cleanly with createUpdate's record-of-handlers, so tags are declared once.

    Type Parameters

    • Spec extends MsgSpec

      The spec record; keys are tags, values are null (no payload) or payload markers.

    Parameters

    • spec: Spec

      The variant spec.

    Returns MsgBuilder<Spec>

    A MsgBuilder whose entries are variant constructors.

    Adding a tag to spec widens MsgOf<typeof builder>. Passing that widened union to createUpdate<MsgOf<...>> makes the missing handler a compile error at the call site, and a missing arm in a switch (msg.kind) is a compile error at assertNever.

    const msg = defineMsgs({
    inc: null,
    dec: null,
    set: payload<{ value: number }>(),
    })
    type CounterMsg = MsgOf<typeof msg>

    msg.inc() // { kind: 'inc' }
    msg.set({ value: 3 }) // { kind: 'set'; value: 3 }