Warning: Effeck is v0. The language will change in major, breaking ways. It is not suitable for production use.

Matching

Matching turns an outcome into one value or selects the next computation. Use typed matching for domain failures and cause matching when a boundary needs defects and interruptions too.

Upstream page

Folding success and failure into values

error InvalidCount

function itemCount(raw: number) {
  if (raw < 0) throw new InvalidCount()
  return raw
}

function countLabel(raw: number) {
  return Effect.match(itemCount(raw), {
    onFailure: () => "Count unavailable",
    onSuccess: (count) => `${count} items`
  })
}
// string!!

Effect.match applies synchronous value callbacks. Neither callback can perform an Effect operation; a callback that only formats text is eligible for plain JavaScript compilation. A cause without an expected failure propagates. If a mixed cause includes an expected failure, Effect selects that failure and can discard its other reasons; ordinary catch preserves the whole mixed cause.

Choosing effectful branches

function reportCount(raw: number) {
  return Effect.matchEffect(() => itemCount(raw), {
    onFailure: () => {
      log("Invalid count received")
      return "Count unavailable"
    },
    onSuccess: (count) => {
      log("Count accepted")
      return `${count} items`
    }
  })
}

matchEffect accepts Effeck functions that can pause, fail, or use services. Only the selected branch runs, and its errors and requirements join the result's contract. A try/catch is also useful when the two branches are easier to read as statements.

Matching complete failure causes

function outcomeLabel() {
  return Effect.matchCause(die(new Error("index invariant")), {
    onFailure: (cause) => cause.hasDies() ? "Index defect" : "Index stopped",
    onSuccess: () => "Index ready"
  })
}

function reportOutcome() {
  return Effect.matchCauseEffect(() => die(new Error("index invariant")), {
    onFailure: (cause) => {
      log("Index stopped", cause.reasons.map((reason) => reason._tag))
      return "Unavailable"
    },
    onSuccess: () => "Ready"
  })
}

matchCause passes the full cause to a synchronous failure callback. matchCauseEffect allows Effect operations in both callbacks. These APIs can consume cancellation and mixed causes, so choose them where that handling is part of the boundary's policy.

Discarding failures or all causes

function ignoreRejectedCount() {
  Effect.ignore(itemCount(-2))
}
// void!!

function discardBoundaryOutcome() {
  Effect.ignoreCause(() => die(new Error("isolated task failed")))
}

ignore discards the success value and typed failures. Causes without an expected failure propagate, but a mixed cause containing one can be consumed too. ignoreCause consumes the full failure cause even when it contains no expected failure. Use complete cause discarding only where losing both diagnostics and cancellation is deliberate.