//#region src/defect.d.ts declare const DEFECT: unique symbol; /** * The opaque marker a `qualify` function returns to triage a cause as * **unexpected**. * * @remarks * `qualify` (passed to {@link fromPromise} / {@link fromThrowable}) returns * `E | Defect`: either a modeled domain error, or a `Defect` produced by the * injected `defect` helper to say "this failure is not modeled". A `Defect` is * opaque — it carries the original cause for the boundary to convert into the * third runtime state of a `Result`. It is **not** a public value; the only way * to mint one is the `defect` helper the boundary passes to `qualify`. * * @internal */ type Defect = { readonly [DEFECT]: true; readonly cause: unknown; }; //#endregion //#region src/matcher.d.ts /** * Cross-copy brand for `P.*` pattern objects: `Symbol.for` yields the same * symbol in every copy of the library (dual CJS/ESM, duplicated install, * another realm), so a pattern built by one copy is recognised by another — * the same rationale as `isResult`'s prototype brand. * * @internal */ declare const PATTERN_BRAND: unique symbol; declare const MATCHES: unique symbol; declare const UNIVERSAL: unique symbol; /** * A `P.*` pattern: a runtime predicate plus the phantom type `M` it matches. * The phantom is declaration-only (never present at runtime); it drives the * type-level narrowing (`Extract`) and exhaustiveness (`Exclude`). * * @typeParam M - the type this pattern matches. * @category Types */ type PatternMatcher = { readonly [PATTERN_BRAND]: (value: unknown) => boolean; readonly [MATCHES]?: M; }; /** * The statically-known universal pattern — the type of `P._` only. * The phantom `UNIVERSAL` marker is *required*, so no other * `PatternMatcher` (e.g. a `P.when` guard that happens to be * universal) is assignable: the catch-all `.with` overload must only fire for * a pattern the type system KNOWS covers everything. * * @category Types */ type UniversalPattern = PatternMatcher & { readonly [UNIVERSAL]: true; }; /** * The type a single pattern matches: a `P.*` matcher's phantom, an object * literal mapped key-by-key (so `{ _tag: "A" }` matches the `"A"`-tagged * variant), or the primitive literal itself. * * @internal */ type MatchedOf = Pt extends PatternMatcher ? M : Pt extends object ? { [K in keyof Pt]: MatchedOf; } : Pt; /** * The diagnostic type of `.exhaustive` on a builder that has NOT covered every * case: not callable (so it fails the `ExhaustiveMatch` constraint at the call * site), and it names the remaining cases so the error reads as a to-do list. * * @internal */ type NonExhaustive = { readonly "unthrown: this match is not exhaustive — add a `.with(…)` for the remaining cases": Remaining; }; /** * The "no output type declared" sentinel for a builder's `Declared` parameter. * A `unique symbol` so no user type can collide with it. Declaration-only — * `tsc` emits it into the `.d.ts` without it needing to be exported. * * @internal */ declare const UNSET: unique symbol; /** @internal */ type Unset = typeof UNSET; /** * A branch handler's return position: free inference (`O2`) while the builder * is unpinned — today's behaviour, unchanged — or the declared type once * `.returnType()` has pinned it. * * `Defect` stays legal under a pin: the injected `defect` helper is the * sanctioned deliberate `Err`→`Defect` form (Thesis #5), and `Defect` is not a * nameable public type, so `returnType()` cannot be spelled. The * marker is subtracted from the output by {@link PinnedOut} — the same net * result as the unpinned `Exclude`, decided up front. * * @internal */ type BranchReturn = [Declared] extends [Unset] ? O2 : Declared | Defect; /** * The builder's output: the accumulated union of branch returns while * unpinned, or the declared type once pinned. * * @internal */ type PinnedOut = [Declared] extends [Unset] ? O : Declared; /** * The diagnostic type of `.returnType` on a builder that already has an output * to contradict — an arm has contributed a return type, or it is already * pinned: not callable, so the mistake is caught where it is written. * * @internal */ type PinTooLate = { readonly "unthrown: `.returnType()` must come before any arm produces an output, and only once": true; }; /** * The match builder over an input union `E`. `Remaining` tracks the cases not * yet covered by a `.with(…)` arm; `O` accumulates the branch output union. * `.exhaustive` is callable only once `Remaining` is `never` — which is what * the `ExhaustiveMatch` constraint requires — and `.run()` executes it. * * @typeParam E - the full input union being matched. * @typeParam Remaining - the cases not yet covered. * @typeParam O - the union of branch return types so far. * @category Types */ type Matcher = { /** * The catch-all arm: `.with(P._, handler)` — the * wildcard **escape hatch**, not the way to handle a concrete error union * (name those cases; `@unthrown/oxlint`'s `no-catch-all-pattern`, in its * `recommended` preset, flags the wildcard). * * It is a **state transition**, not a computation — it returns * `Matcher` with the remaining cases literally `never`, so the * builder is provably exhaustive even when `E` is an unresolved type * parameter (a lazily-deferred `Exclude` would not resolve * there). That is what makes it irreplaceable for a helper generic in `E`: * it can terminate a match no arm list could (issue #145) — one of the two * sanctioned uses (see {@link P}). */ with(pattern: UniversalPattern, handler: (value: Remaining) => BranchReturn): Matcher; /** * Add an arm: one or more patterns sharing a single handler (grouped * patterns — `matcher.with(P.tag("A"), P.tag("B"), handler)`). The handler * receives the input narrowed to what the patterns match (computed against * `Remaining`, so cases already handled by earlier arms are excluded); the * matched cases are subtracted from `Remaining`. */ with(...args: [...patterns: Pts, handler: (value: Extract>) => BranchReturn]): Matcher>, O | O2, Declared>; /** * Declare the match's output type up front: every subsequent branch handler * is checked against `R`, and the match evaluates to `R` instead of the * union of whatever the branches happened to return. * * @remarks * Reach for it when the output is **decided by a signature rather than by * the branches** — most sharply in code generic in `E`, where the fold's type * has to be declared. It also stops a drifting branch from silently widening * the outgoing type, reports the mismatch **on the offending branch**, and * gives branch returns a contextual type (so object literals need no * annotation). * * A branch may still return the injected `defect` helper's marker; the defect * channel is not part of the declared output. * * Callable **before any arm has produced an output**, and only once * (mirroring ts-pattern's up-front pin): once there is an inferred output for * the pin to contradict — or the builder is already pinned — this is typed as * a non-callable diagnostic. In practice that means calling it directly after * `match(…)`; the gate is about output rather than position, so an earlier arm * whose handler returns `never` (it always throws) contributes nothing and * does not close it — sound, since a `never` branch can contradict no declared * type. A no-op at runtime. * * @typeParam R - the declared output type of every branch. */ returnType: [O] extends [never] ? [Declared] extends [Unset] ? () => Matcher : PinTooLate : PinTooLate; /** * Terminate the match. Typed callable only when every case is covered * (`Remaining` is `never`); otherwise it is a branded diagnostic object * naming the remaining cases, and the builder fails the `ExhaustiveMatch` * constraint at the combinator call site. */ exhaustive: [Remaining] extends [never] ? () => PinnedOut : NonExhaustive; /** * Execute the match (the combinators call this; it runs `.exhaustive()`). * A value with no matching arm throws {@link NonExhaustiveError} — * unreachable for well-typed callers. */ run(): PinnedOut; }; /** * Thrown by `.run()` / `.exhaustive()` when no arm matched the value. For * well-typed callers the match is exhaustive by construction, so this is only * reachable by a value that slipped past the types (a widened cast, a raw-JS * caller); inside the error combinators the throw-to-defect net converts it to * a `Defect`, and at the `match` edge it surfaces (a genuinely unmodeled value * is a bug). * * @category Errors */ declare class NonExhaustiveError extends Error { /** The value no arm matched. */ readonly input: unknown; constructor(input: unknown); } /** * Begin a match over `value`. Chain `.with(pattern, …patterns, handler)` arms; * terminate with `.exhaustive()` — or return the un-terminated builder to an * unthrown error combinator / `match({ errCases })`, which runs it for you. * * @remarks * This is unthrown's own matcher (the former ts-pattern re-export): the same * call-site shape, with exhaustiveness computed by plain `Exclude` over the * builder's `Remaining` parameter. Name every case of the input union; the * `P._` catch-all is the escape hatch, and is provably exhaustive even over an * unresolved generic input — one of the two cases it is irreplaceable for (see * {@link P}). * * @category Constructors */ declare function match(value: E): Matcher; /** * The pattern namespace (unthrown's own; the former ts-pattern `P`): * * - `P._` — the universal catch-all, and an **escape hatch** rather * than the default: matching the error channel means naming its cases, so * reach for this only where they cannot be named. Matches anything, and * (because its phantom type is `unknown`) makes the builder provably * exhaustive even when the matched input is an unresolved type parameter. * Two situations are legitimate: a **helper generic in `E`**, where no arm * list can prove exhaustiveness against an unresolved type parameter; and an * **`E` that is a single type**, not a union of cases (a validator's issues * array, say), where one arm _is_ the enumeration. `@unthrown/oxlint`'s * `no-catch-all-pattern` (in its `recommended` preset) flags every other use; * keep the deliberate ones behind a targeted `oxlint-disable` saying which of * the two it is. * - `P.tag(value: Tag): { _tag: Tag }` — the * `{ _tag: t }` object pattern, matching any value whose `_tag` equals `t` (a * `TaggedError`, or any `_tag`-discriminated member) and narrowing the * branch's parameter to that variant, payload included. The workhorse of the * error channel: `matcher.with(P.tag("NotFound"), (e) => …)`. It composes like * any other pattern — in a grouped arm * (`.with(P.tag("A"), P.tag("B"), handler)`). * - `P.instanceOf(Cls)` — an `instanceof` check, narrowing to the class * instance type (for union members that are not tagged, e.g. a third-party * error class). * - `P.when(guard)` — an arbitrary type-guard predicate. Also the way to match * a primitive shape (`P.when((v): v is string => typeof v === "string")`), * and grouping patterns under one handler is what a `.with(a, b, handler)` * arm already does. * * @category Constructors */ declare const P: Readonly<{ _: UniversalPattern; tag: (value: Tag) => { _tag: Tag; }; instanceOf: unknown>(cls: C) => PatternMatcher>; when: (guard: (value: unknown) => value is G) => PatternMatcher; }>; //#endregion //#region src/types.d.ts /** * Flatten an intersection into a single object literal so accumulated `bind` / * `let` scopes display cleanly (`{ a; b }` rather than `{ a } & { b }`). * * @internal */ type Prettify = { [K in keyof T]: T[K]; } & {}; /** * The scope produced by a `bind` / `let` step: `T` with `K` added (as a readonly * property of type `U`). `Omit` first drops any existing `K`, so re-binding * a name **overwrites** it — matching the runtime spread — rather than producing * an unsound `T[K] & U` intersection. * * @internal */ type Bound = Prettify & { readonly [P in K]: U; }>; /** * Compile-time rejection of a thenable callback result — the type-level * enforcement of "combinator callbacks are synchronous" (see the * {@link AsyncResult} remarks). * * @remarks * Resolves to `unknown` (a no-op in an intersection) for any non-thenable `R`, * and to an explanatory string-literal type when `R` is a `PromiseLike` — so an * `async` callback fails to compile with the explanation in the error. Without * this, `async () => …` would be assignable to `() => void`, and its rejection * would escape the pipeline as an unhandled rejection instead of a `Defect`. * Lift async work with {@link fromPromise} and compose it with `flatMap`. * * Spelled with `Extract`, not `[R] extends [PromiseLike<…>]`, so the ban also * fires when only SOME arms of a union return are thenable — a *sometimes*-async * callback (`flag ? 1 : work()`) is still an unawaited effect whose rejection * the pipeline never sees. The tuple-wrapped form is false for a partial union * and let exactly that through. This is the same reasoning `fromPromise`'s * async-qualify guard already used. * * @typeParam R - the callback's inferred return type. * @category Types */ type NotThenable = [Extract>] extends [never] ? unknown : "unthrown: combinator callbacks are synchronous — lift async work with fromPromise and compose with flatMap"; /** * The built-in match builder over an error union `E`, as produced by * `match(error)`. This is what an error combinator's callback receives — chain * `.with(pattern, handler)` on it; the combinator itself calls `.exhaustive()`, * so the callback returns the **un-terminated** builder. * * @remarks * Named via `ReturnType>` (i.e. `Matcher`), * keeping this alias stable however the builder evolves. * * @typeParam E - the error union being matched. * @category Types */ type ErrMatcher = ReturnType>; /** * The shape an error-combinator callback must return: an **exhaustive** * match builder. `exhaustive` is required to be *callable* — on a builder * that hasn't covered every case the matcher types it as a branded diagnostic * (not a function), so a non-exhaustive chain fails to satisfy this and errors * at the call site. `run` carries the output type. * * @typeParam O - the union of the branch return types (the builder's output). * @internal */ type ExhaustiveMatch = { exhaustive: (...args: never[]) => unknown; run: () => O; }; /** * The output of an `ExhaustiveMatch` — the union of its branch returns. * * @internal */ type MatchOut = M extends ExhaustiveMatch ? O : never; /** * The outgoing modeled-error type a transforming match produces: the builder's * output with the `Defect` arm **subtracted** (`Exclude`, the same * inference as the boundary `qualify`, Thesis #3). A branch that returns * `defect(cause)` therefore contributes nothing to the modeled channel. * * @internal */ type MatchErrOut = Exclude, Defect>; /** * The fluent method surface every {@link Result} variant carries — the * combinators (`map`, `flatMap`, `mapErrCases`, `match`, `get`, …), documented one * per entry below. Factored out so the three variants ({@link OkView}, * {@link ErrView}, {@link DefectView}) can each intersect it; {@link AsyncResult} * mirrors this surface with async signatures. * * @remarks * This type exists to **document** the surface and to power narrowing — not to be * authored against. You obtain it by holding a `Result` (or `AsyncResult`), never * by implementing your own `Result`-like; treat it as read-only reference. * * @typeParam T - the success value type. * @typeParam E - the modeled error type. * @category Methods */ type ResultMethods = { /** * Transform the success value with `f`. * * Runs `f` only on `Ok`; `Err` and `Defect` pass through untouched. If `f` * throws, the thrown value is captured as a `Defect`. * * An async callback is rejected at compile time ({@link NotThenable}). * * @typeParam U - the mapped success type. * @param f - maps the current success value to a new one. */ map(f: (value: T) => U & NotThenable): Result$1; /** * Sequence a dependent, `Result`-returning step (monadic bind). * * Runs `f` only on `Ok`; `Err` and `Defect` pass through. The error channels * combine, widening to `E | E2`. If `f` throws, the throw becomes a `Defect`. * * @typeParam U - the success type of the next step. * @typeParam E2 - the error type the next step may introduce. * @param f - produces the next `Result` from the current success value. */ flatMap(f: (value: T) => Result$1): Result$1; /** * Run a side effect on the success value and pass the `Result` through * unchanged. * * Runs only on `Ok`. If `f` throws, the throw becomes a `Defect`. An async * callback is rejected at compile time ({@link NotThenable}). * * @remarks * `f`'s return value is **ignored** — a `Result` returned by the effect * compiles but is discarded, `Err` and all. If the effect can fail, sequence * it instead of tapping it: a `Result`-returning effect goes in * {@link ResultMethods.flatTap | flatTap}; an `AsyncResult`-returning effect * cannot be sequenced from the sync surface — lift the chain with * {@link ResultMethods.toAsync | toAsync} and use the async * {@link AsyncResultMethods.flatTap | flatTap} (which accepts both). * * @param f - the side effect (its return value is ignored). */ tap(f: (value: T) => R & NotThenable): Result$1; /** * Run a **failable** side effect on the success value, keeping the original * value but threading the effect's error. * * @remarks * This is to {@link ResultMethods.tap | tap} what * {@link ResultMethods.flatMap | flatMap} is to {@link ResultMethods.map | map}: * `f` returns a `Result`, but its **success value is discarded** — on success * the original value flows through (`Result`), while an `Err` (or * `Defect`) from `f` short-circuits. Runs only on `Ok`; `Err` and `Defect` pass * through. If `f` throws, the throw becomes a `Defect`. Use it for a validation * or write whose _result_ matters but whose _value_ you don't need. * * @typeParam E2 - the error type the effect may introduce. * @param f - the failable side effect; its `Ok` value is ignored. */ flatTap(f: (value: T) => Result$1): Result$1; /** * Do-notation: run `f` for a `Result` and **bind its value** under `name` in * an accumulating object scope. * * @remarks * Begin a chain with {@link Do} (an empty object scope) and grow it step by * step. `f` receives the scope accumulated so far and returns a `Result`; on * `Ok` the value is added as `{ ...scope, [name]: value }`, on `Err`/`Defect` * the chain short-circuits. Errors union (`E | E2`). A throw becomes a * `Defect` — as does calling `bind` on a non-object scope (e.g. `Ok(5).bind`), * which is misuse: the scope is always an object inside a real `Do()` chain. * (`let` is the pure-value counterpart.) * * @typeParam K - the key the bound value is stored under. * @typeParam U - the bound value type. * @typeParam E2 - the error type `f` may introduce. * @param name - the scope key. * @param f - produces a `Result` from the accumulated scope. */ bind(name: K, f: (scope: T) => Result$1): Result$1, E | E2>; /** * Do-notation: run `f` for a **plain value** and bind it under `name` in the * accumulating object scope. The pure-value counterpart of {@link ResultMethods.bind | bind}. * * @remarks * `f` receives the scope and returns a value (not a `Result`); it is added as * `{ ...scope, [name]: value }`. Runs only on `Ok`; `Err`/`Defect` pass * through. A throw becomes a `Defect`. An async callback is rejected at * compile time ({@link NotThenable}). * * @typeParam K - the key the value is stored under. * @typeParam U - the value type. * @param name - the scope key. * @param f - computes a value from the accumulated scope. */ let(name: K, f: (scope: T) => U & NotThenable): Result$1, E>; /** * Replace the success value with a constant `value`. * * Runs only on `Ok`; `Err` and `Defect` pass through. * * @typeParam U - the replacement value type. */ as(value: U): Result$1; /** * Drop the success value, collapsing the success type to `void`. * * The named form of `map(() => undefined)`. Runs only on `Ok` (the value is * replaced with `undefined`); `Err` and `Defect` pass through. Unlike * `as(undefined)` — which produces `Result` — the success type * is `void`: the value's story ends here. */ discard(): Result$1; /** * Validate the success value — keep the `Ok` when `predicate` holds, * otherwise fail into the **modeled** channel with `Err(onFail(value))`. * * @remarks * The named form of `flatMap((v) => (p(v) ? Ok(v) : Err(e)))`. With a * **type-guard** predicate (`(v): v is U`) the success type is **refined** to * `U` on the way through (this overload). Runs only on `Ok` — a passing value * flows through as the *same* `Ok`; `Err` and `Defect` pass through * untouched. A throw in `predicate` or `onFail` becomes a `Defect`. * * Both callbacks are synchronous: an async `onFail` is rejected at compile * time ({@link NotThenable}), and an async predicate does not type-check * either — its `Promise` is not a `boolean` (and, being truthy, * would have silently always passed). * * @typeParam U - the refined success type (type-guard form). * @typeParam E2 - the error type `onFail` produces. * @param predicate - the check; a type guard refines `T` to `U`. * @param onFail - maps the failing value to the modeled error. * * @example * ```ts * // boolean form: gate a value * Ok(-1).ensure((n) => n > 0, (n) => `negative: ${n}`); // Err("negative: -1") * * // type-guard form: refine the success type * declare const r: Result; * const s = r.ensure( * (v): v is string => typeof v === "string", * () => "not_a_string" as const, * ); // Result * ``` */ ensure(predicate: (value: T) => value is U, onFail: (value: T) => E2 & NotThenable): Result$1; /** * Boolean form of {@link ResultMethods.ensure | ensure} — validates without * refining, keeping the success type `T`. */ ensure(predicate: (value: T) => boolean, onFail: (value: T) => E2 & NotThenable): Result$1; /** * Transform the modeled error by **matching it exhaustively**. * * @remarks * The callback receives `match(error)` (an {@link ErrMatcher}) and the * injected `defect` helper. Chain `.with(pattern, handler)` and **return the * un-terminated builder** — `mapErrCases` calls `.exhaustive()` itself, so a * missing case is a compile error at the call site (there is no `.exhaustive()` * to forget, and no way to slip in `.otherwise()`). The outgoing error type is * the union of the branch returns with the `Defect` arm subtracted * (`Exclude`) — a branch returning `defect(cause)` converts that case * to a `Defect` and drops it from `E`. Runs only on `Err`; `Ok` and `Defect` * pass through. A branch that throws also becomes a `Defect`. * * **Name every case.** Match on anything the matcher supports — `_tag`, * `code`, structural shape, guards — and group the cases that share a handler * with `.with(a, b, handler)`. `.with(P._, …)` is the wildcard **escape * hatch**, not the default: it makes any match exhaustive, so it also absorbs * every case `E` grows later. Two uses are sanctioned — a helper generic in * `E`, where no arm list can prove exhaustiveness against an unresolved type * parameter, and an `E` that is a single type rather than a union of cases * (see {@link P} for both). `@unthrown/oxlint`'s `no-catch-all-pattern` (in * its `recommended` preset) flags the rest. * * @typeParam M - the exhaustive builder the callback returns. * @param f - builds the match over the error (returns the un-terminated builder). */ mapErrCases>(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => M): Result$1>; /** * Sequence from an `Err` by producing another `Result` — the error-channel * mirror of {@link ResultMethods.flatMap | flatMap}, **matching the error * exhaustively** ({@link ErrMatcher}; the combinator calls `.exhaustive()`). * * Each branch returns a `Result`; the outgoing channels are the unions of the * branch-returned `Result`s' channels. A branch may return `defect(cause)`. * Runs only on `Err`; `Ok` and `Defect` pass through. * * @typeParam M - the exhaustive builder the callback returns. * @param f - builds the match; each branch produces a fallback `Result`. */ flatMapErrCases | Defect>>(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => M): Result$1>, ErrOf>>; /** * Recover from an `Err` by producing a success value, emptying the error * channel — **matching the error exhaustively** ({@link ErrMatcher}). Pairs * with {@link ResultMethods.recoverDefect | recoverDefect}. * * @remarks * The result type is `Result`, but `never` describes only the * **error** channel — a `Defect` can still be present at runtime. A branch may * return `defect(cause)` (which stays a `Defect`, not a recovery). Runs only on * `Err`; `Ok` and `Defect` pass through. * * @typeParam M - the exhaustive builder the callback returns. * @param f - builds the match; each branch produces a success value. */ recoverErrCases>(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => M): Result$1, never>; /** * Run a side effect on the error — **matched exhaustively** ({@link ErrMatcher}) * — and pass the `Result` through unchanged. * * @remarks * The callback builds a match whose branches run side effects; their return * values are ignored and the original `Err` flows through. Exhaustive like the * transformers, and like them it wants every case named — `.with(P._, …)` * remains the wildcard escape hatch. If a branch throws, the * result is a `Defect` whose cause is an `AggregateError` of `[thrown, original * failure]` — observing a failure never destroys it. An **async branch is * rejected at compile time** ({@link NotThenable} on the builder output): * because the branch results are discarded, a returned `Promise` would float * unobserved and its rejection would vanish. The one branch return that is * **not** discarded is the injected `defect(cause)` marker: it is the * lint-clean, expression-position form of a `throw`, so it follows the throw * rule above (an `AggregateError` of `[the branch's cause, original * failure]`), never a silent no-op. A failable * `Result`-returning effect belongs in * {@link ResultMethods.flatTapErrCases | flatTapErrCases}. * * @param f - builds the match; branch returns are ignored, bar `defect(cause)`. */ tapErrCases(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => ExhaustiveMatch>): Result$1; /** * Run a **failable** side effect on the error, keeping the original error but * threading the effect's own error — **matched exhaustively** * ({@link ErrMatcher}). * * @remarks * The error-channel mirror of {@link ResultMethods.flatTap | flatTap}: each * branch returns a `Result` whose **success value is discarded** — on the * effect's `Ok` the original `Err` flows through, while an `Err`/`Defect` from a * branch short-circuits and threads its error. Note the asymmetry with a * *throw*: a branch that **returns** a Defect-state `Result` **replaces** the * original `Err` (Defect-dominance, the short-circuit rule — it is not * aggregated), whereas a branch that **throws** produces a `Defect` * aggregating `[thrown, original failure]` (observing a failure by throwing * never destroys it). A branch returning the injected `defect(cause)` marker — * reachable under a `returnType` pin — follows the *throw* rule, since it is * the lint-clean, expression-position form of one. * * @typeParam M - the exhaustive builder the callback returns. * @param f - builds the match; each branch is a failable effect (its `Ok` is ignored). */ flatTapErrCases(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => ExhaustiveMatch>): Result$1; /** * Recover from a `Defect` — the **only** combinator that can touch one. * * @remarks * Runs `f` only when a `Defect` is present, re-entering the modeled world by * returning a `Result` (an `Ok` or a fresh `Err`). `Ok` and `Err` pass * through. Recovering a Defect should be rare: usually you let it bubble to * the edge. If `f` throws, the throw becomes a new `Defect`. * * @typeParam U - a success type the recovery may produce. * @typeParam E2 - an error type the recovery may produce. * @param f - maps the Defect's unknown cause to a recovering `Result`. */ recoverDefect(f: (cause: unknown) => Result$1): Result$1; /** * Run a side effect on a present `Defect`'s cause (e.g. logging) and pass the * `Defect` through unchanged. If `f` throws, the result is a `Defect` whose * cause is an `AggregateError` of `[thrown, original failure]` — observing a * failure never destroys it. An async callback is rejected at compile time * ({@link NotThenable}). * * @param f - the side effect over the unknown cause. */ tapDefect(f: (cause: unknown) => R & NotThenable): Result$1; /** * Run a side effect on **any failure** — `Err` or `Defect` — and pass the * `Result` through unchanged. The one cross-channel observer, for the shared * "it went KO" concern (logging, metrics, rollback) that would otherwise be * duplicated across {@link ResultMethods.tapErrCases | tapErrCases} and * {@link ResultMethods.tapDefect | tapDefect}. * * @remarks * `f` receives the narrowed **failure variant** ({@link FailureView}), not a * payload — the payload union `E | unknown` would collapse to `unknown` and * lose `E`'s typing. Branch on `failure.tag` to reach the typed payload * (`"Err"` → `failure.error: E`, `"Defect"` → `failure.cause: unknown`), or * treat it opaquely for a shared logger. Runs on `Err` and `Defect`; `Ok` * passes through. It **observes without consuming**: the failure flows on * unchanged — to also recover, use * {@link ResultMethods.recoverErrCases | recoverErrCases} / * {@link ResultMethods.recoverDefect | recoverDefect} (deliberately separate * acts) or {@link ResultMethods.match | match} at the edge. If `f` throws, the * result is a `Defect` whose cause is an `AggregateError` of `[thrown, * original failure]` — observing a failure never destroys it. An async * callback is rejected at compile time ({@link NotThenable}). * * @param f - the side effect over the failure variant (its return value is ignored). */ tapFailure(f: (failure: FailureView) => R & NotThenable): Result$1; /** * Exhaustively fold all three runtime states into a single value. * * @remarks * Exactly one handler runs. Together with the throw-to-Defect guarantee, this * is typically the single place a pipeline is handled at the edge — mapping * `Ok`/`Err`/`Defect` to (for example) 2xx / 4xx / 5xx with no `try`/`catch`. * * The `errCases` handler does not take a single blanket callback: it receives * `match(error)` (an {@link ErrMatcher}) and **matches the error exhaustively**, * exactly like the error combinators — which is why the key carries the same * `…Cases` suffix. Chain `.with(pattern, handler)` and **return the * un-terminated builder** — `match` calls `.exhaustive()` itself, so a missing * case is a compile error at the call site (no `.exhaustive()` to forget). * Folding at the edge names every case too — `.with(P._, …)` is the wildcard * escape hatch, not the default. Unlike the combinators the branches * receive **no `defect` helper** — `match` is total elimination to a value, * with no `Defect` output channel; the `defect` case handles a `Result` that * already carries one. (A `Result` is also a discriminated union — for richer * whole-`Result` matching, `match(result).with(…)`.) * * @typeParam ROk - the `ok` handler return type. * @typeParam RDefect - the `defect` handler return type. * @typeParam M - the exhaustive builder the `errCases` handler returns. * @param cases - the `ok`/`defect` handlers plus the `errCases` matcher builder. */ match>(cases: { ok: (value: T) => ROk; errCases: (matcher: ErrMatcher) => M; defect: (cause: unknown) => RDefect; }): ROk | RDefect | MatchOut; /** * Extract the success value. * * @remarks * Compiles only when the error channel is empty (`E = never`) — eliminate * modeled errors first (`match` / `recoverErrCases` / `flatMapErrCases`), or reach for the * `getOr` / `getOrElse` / `getOrNull` / `getOrUndefined` family (which * recover an `Err`). If you get a `'this' context` type error here, that is * the gate: the receiver still has a non-`never` error channel. * * `E = never` empties only the **modeled** error channel — a `Defect` can * still be present, and `get()` **rethrows its original cause** (it * _panics_); `Result` does not mean `get()` cannot throw. * * @returns the `Ok` value. */ get(this: Result$1): T; /** * Extract the modeled error. * * @remarks * Compiles only when the success channel is empty (`T = never`) — eliminate * the success case first. `T = never` is rarely the case in practice (a * `Result` you hold usually still has a success type), so to inspect an * error prefer an `isErr()` guard or, in tests, `@unthrown/vitest`'s * `toBeErrWith`. A `Defect` still **rethrows its original cause** (a defect is * a bug, not an absent value), so this does not mean `getErr()` can't throw. * * @returns the `Err` value. */ getErr(this: Result$1): E; /** * The success value, or `fallback` on `Err`. * * @typeParam U - the fallback type (may differ from `T`; the return widens to `T | U`). * @param fallback - returned when the result is an `Err` (may be a different type; the return widens to `T | U`). * @throws Re-throws on a `Defect` — a Defect is a bug, not an absent value, so * it is never silently replaced. */ getOr(fallback: U): T | U; /** * The success value, or `f(error)` on `Err`. * * @typeParam U - the fallback type (may differ from `T`; the return widens to `T | U`). * @param f - lazily computes the fallback from the error (may return a different type; the return widens to `T | U`). * @throws Re-throws on a `Defect`. */ getOrElse(f: (error: E) => U): T | U; /** * The success value, or `null` on `Err`. * * @throws Re-throws on a `Defect`. */ getOrNull(): T | null; /** * The success value, or `undefined` on `Err`. * * @throws Re-throws on a `Defect`. */ getOrUndefined(): T | undefined; /** * The success value, or **throw** the modeled error on `Err`. * * @remarks * A deliberate escape hatch off the errors-as-values model — it **throws the * `Err` value as-is** at the call site, so a caller of the enclosing function * sees a throw rather than a channel. Its home is **tests and scripts**, * where "this `Result` had better be `Ok`" is the assertion and a throw is * the correct failure mode. * * In production code, fold the error channel instead: * {@link ResultMethods.recoverErrCases | recoverErrCases} empties `E`, so * {@link ResultMethods.get | get} compiles and a case routed to the injected * `defect(...)` panics with its original cause — with every case still named. * {@link ResultMethods.match | match} and * {@link ResultMethods.flatMapErrCases | flatMapErrCases} are the other two * ways to keep the error a value. `@unthrown/oxlint`'s opt-in * `no-get-or-throw` rule enforces this, exempting test files through an * oxlint `overrides` entry. * * Type-gated as the **complement** of {@link ResultMethods.get | get}: it * compiles only when the error channel is **non-empty** (`E` is not `never`) — * there must be a modeled error for it to throw. On a `Result` there * is nothing to throw, so `getOrThrow` does not compile; use `get()` (which * gates the other way). Together they partition extraction by the error * channel's state, with no overlap. * * @returns the `Ok` value. * @throws the modeled `error` on `Err`; re-throws the original `cause` on a * `Defect` (a panic, like the rest of the `getOr…` family). */ getOrThrow(this: [E] extends [never] ? "unthrown: getOrThrow is unnecessary here — the Err channel is empty (E = never), so there is nothing to throw. Use get() instead." : Result$1): T; /** Whether this result is `Ok` — narrows `this` to its {@link OkView} on `true`. */ isOk(): this is OkView; /** Whether this result is `Err` — narrows `this` to its {@link ErrView} on `true`. */ isErr(): this is ErrView; /** Whether this result is a `Defect` — narrows `this` to its {@link DefectView} on `true`. */ isDefect(): this is DefectView; /** Lift this synchronous `Result` into an {@link AsyncResult}. */ toAsync(): AsyncResult$1; }; /** * The `Ok` variant of a {@link Result}: a success carrying a `value`. This is * what a successful `isOk` guard narrows to, making `.value` reachable. It also * carries the shared fluent surface ({@link ResultMethods}). * * @example * ```ts * if (r.isOk()) r.value; // r: OkView here — .value is a T * ``` * * @category Types */ interface OkView extends ResultMethods { readonly tag: "Ok"; readonly value: T; } /** * The `Err` variant of a {@link Result}: a modeled failure carrying an `error`. * This is what a successful `isErr` guard narrows to, exposing `.error`. It also * carries the shared fluent surface ({@link ResultMethods}). * * @remarks * **Note the parameter order: `ErrView` puts the error type _first_** — the * reverse of the `` order used by {@link OkView}, {@link DefectView}, and * {@link Result} — because `Result` narrows to `ErrView` (the error is * the payload the guard makes reachable). You rarely write it by hand (a failed * `isErr()` narrows to it for you); if you do, mind the flip — `ErrView`, not `ErrView`. * * @example * ```ts * if (r.isErr()) r.error; // r: ErrView here — .error is an E * ``` * * @category Types */ interface ErrView extends ResultMethods { readonly tag: "Err"; readonly error: E; } /** * The `Defect` variant of a {@link Result}: an unmodeled failure carrying a * `cause`. This is what a successful `isDefect` guard narrows to, exposing * `.cause`. It also carries the shared fluent surface ({@link ResultMethods}). * * @example * ```ts * if (r.isDefect()) r.cause; // r: DefectView here — .cause is `unknown` * ``` * * @category Types */ interface DefectView extends ResultMethods { readonly tag: "Defect"; readonly cause: unknown; } /** * A failure variant of a {@link Result}: an {@link ErrView} **or** a * {@link DefectView}. This is what a `tapFailure` callback receives — the * discriminated variant rather than a payload, because the payload union * `E | unknown` would collapse to `unknown` and lose `E`'s typing. Branch on * `tag` to narrow (`"Err"` → `.error: E`, `"Defect"` → `.cause: unknown`). * * @remarks * Like {@link ErrView}, the error type comes **first** (`FailureView`) — * the error is the payload you are usually here for, and a shared observer can * spell just `FailureView`. * * @example * ```ts * const logKo = (f: FailureView) => * f.tag === "Err" ? logger.warn(f.error) : logger.error(f.cause); * result.tapFailure(logKo); * ``` * * @typeParam E - the modeled error type. * @typeParam T - the success value type (phantom here; a failure carries none). * @category Types */ type FailureView = ErrView | DefectView; /** * The core type of the library: a computation that has either succeeded with a * value of type `T` or failed with a *modeled* error of type `E`. * * @remarks * A `Result` is a **discriminated union** of three variants, distinguished by a * `tag` of `"Ok"` | `"Err"` | `"Defect"`: * * - **`Ok`** — a success carrying a `value: T`. * - **`Err`** — a modeled, anticipated failure carrying an `error: E`. * - **`Defect`** — an *unmodeled* failure carrying an unknown `cause`. A Defect * never appears in `E`; it is the library's third, out-of-band channel. * * Because it is a real union, you can match it natively (a `switch` on `tag`, or * the built-in `match(...).with({ tag: "Ok" }, …).exhaustive()`), *and* it * carries the full method surface ({@link ResultMethods}) for fluent chaining. * Either way, the payload (`value`/`error`/`cause`) is only reachable after you * narrow — so "check before you access" still holds. * * @typeParam T - the success value type. * @typeParam E - the modeled error type (only anticipated domain failures). * * @example * ```ts * import { Ok, Err, type Result } from "unthrown"; * * function half(n: number): Result { * return n % 2 === 0 ? Ok(n / 2) : Err("odd"); * } * * const message = half(10).match({ * ok: (n) => `got ${n}`, * // every case of `E` named — here the one literal it holds * errCases: (matcher) => matcher.with("odd", () => "failed: odd"), * defect: (cause) => `bug: ${String(cause)}`, * }); * ``` */ type Result$1 = OkView | ErrView | DefectView; /** * A success-only thenable: awaitable, but deliberately **not** a full * `PromiseLike`. * * @remarks * An {@link AsyncResult}'s internal promise never rejects, so `await`-ing one * always yields a {@link Result} and never throws — there is no rejection * channel to model, and none is advertised. At runtime it is still a thenable * (the only way `await` can collapse it), and `Promise.all` / `Promise.resolve` * will still adopt it — harmlessly, since it settles to a `Result` and never * rejects. What the narrowing prevents is treating it as a full promise: * `.catch()` / `.finally()` do not type-check, because there is no rejection to * handle. * * @typeParam T - the value `await` resolves to. * * @category Types */ type Awaitable = { then(onfulfilled?: ((value: T) => R | PromiseLike) | null): PromiseLike; }; /** * The async method surface every {@link AsyncResult} carries — the combinators * (`map`, `flatMap`, `mapErrCases`, `match`, `get`, …) with their asynchronous * signatures, documented one per entry below. The async mirror of * {@link ResultMethods}: each entry links its synchronous counterpart and states * only the async delta. * * @remarks * Like {@link ResultMethods}, this type exists to **document** the surface — not * to be authored against; you obtain it by holding an `AsyncResult`. Its * combinator callbacks are **synchronous** (a raw `Promise` may never enter — see * the {@link AsyncResult} remarks); async work re-enters via {@link fromPromise} * and composes with `flatMap`. Systematic differences from the sync surface: the * binds return an `AsyncResult` (and additionally accept one), and the * eliminators return a `Promise`. * * @typeParam T - the success value type. * @typeParam E - the modeled error type. * @category Methods */ type AsyncResultMethods = { /** * Asynchronous {@link ResultMethods.map | map}: transforms the success value * with `f`. `f` is synchronous; a throw becomes a `Defect`. An async callback * is rejected at compile time ({@link NotThenable}). */ map(f: (value: T) => U & NotThenable): AsyncResult$1; /** * Asynchronous {@link ResultMethods.flatMap | flatMap}. Unlike the sync form, * `f` may return a `Result` **or** an `AsyncResult` (never a raw `Promise`); a * throw becomes a `Defect`. * * @remarks * The async branch of `f`'s return type is spelled `Awaitable> & * { flatMap: unknown }` rather than `AsyncResult`: this is what you get * by returning an `AsyncResult` (it satisfies both), but inference runs through * the `Awaitable` then-channel so `U`/`E2` stay precise instead of collapsing * to `unknown`, while the `{ flatMap: unknown }` marker still rejects a bare * `Promise` (it has no `flatMap`). Just return a `Result` or an `AsyncResult`. */ flatMap(f: (value: T) => Result$1 | (Awaitable> & { flatMap: unknown; })): AsyncResult$1; /** * Asynchronous {@link ResultMethods.tap | tap}. `f` is synchronous; a throw * becomes a `Defect`. An async callback is rejected at compile time * ({@link NotThenable}) — and so is a returned `AsyncResult` (it is * awaitable). Beware the near-miss: _calling_ an `AsyncResult`-returning * effect inside the callback without returning it compiles and leaves the * effect floating — fire-and-forget, never awaited, its `Err`/`Defect` * unobserved. If the effect returns a `Result`/`AsyncResult`, use * {@link AsyncResultMethods.flatTap | flatTap}. */ tap(f: (value: T) => R & NotThenable): AsyncResult$1; /** * Asynchronous {@link ResultMethods.flatTap | flatTap} — a failable tap that * keeps the original value. `f` may return a `Result` **or** an `AsyncResult`; * its `Ok` value is discarded, an `Err`/`Defect` short-circuits, and a throw * becomes a `Defect`. */ flatTap(f: (value: T) => Result$1 | (Awaitable> & { flatMap: unknown; })): AsyncResult$1; /** * Asynchronous {@link ResultMethods.bind | bind} (do-notation). `f` may return * a `Result` **or** an `AsyncResult`; its value is bound under `name` in the * accumulating scope. */ bind(name: K, f: (scope: T) => Result$1 | (Awaitable> & { flatMap: unknown; })): AsyncResult$1, E | E2>; /** * Asynchronous {@link ResultMethods.let | let} (do-notation). `f` returns a * plain value, bound under `name`. An async callback is rejected at compile * time ({@link NotThenable}). */ let(name: K, f: (scope: T) => U & NotThenable): AsyncResult$1, E>; /** Asynchronous {@link ResultMethods.as | as}: replaces the value with `value`. */ as(value: U): AsyncResult$1; /** Asynchronous {@link ResultMethods.discard | discard}: drops the value, collapsing the success type to `void`. */ discard(): AsyncResult$1; /** * Asynchronous {@link ResultMethods.ensure | ensure}: validate the success * value — and, with a type-guard predicate (this overload), **refine** it — * failing into the modeled channel with `Err(onFail(value))`. Both callbacks * are synchronous (an async `onFail` is rejected at compile time, * {@link NotThenable}); a throw in either becomes a `Defect`. */ ensure(predicate: (value: T) => value is U, onFail: (value: T) => E2 & NotThenable): AsyncResult$1; /** Boolean form of the asynchronous {@link ResultMethods.ensure | ensure} — validates without refining, keeping `T`. */ ensure(predicate: (value: T) => boolean, onFail: (value: T) => E2 & NotThenable): AsyncResult$1; /** * Asynchronous {@link ResultMethods.mapErrCases | mapErrCases} — the same exhaustive * {@link ErrMatcher} form; the combinator calls `.exhaustive()`. */ mapErrCases>(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => M): AsyncResult$1>; /** * Asynchronous {@link ResultMethods.flatMapErrCases | flatMapErrCases} — the same * exhaustive {@link ErrMatcher} form. Unlike the sync form, a branch may * return a `Result` **or** an `AsyncResult`. */ flatMapErrCases | AsyncResult$1 | Defect>>(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => M): AsyncResult$1> | AsyncOkOf>, ErrOf> | AsyncErrOf>>; /** * Asynchronous {@link ResultMethods.recoverErrCases | recoverErrCases} — the same * exhaustive {@link ErrMatcher} form. Branches are synchronous; a throw * becomes a `Defect`. */ recoverErrCases>(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => M): AsyncResult$1, never>; /** * Asynchronous {@link ResultMethods.tapErrCases | tapErrCases}. `f` is synchronous; if it * throws — or a branch returns the injected `defect(cause)` marker, the * expression-position form of a throw — the result is a `Defect` whose cause * is an `AggregateError` of `[thrown, original failure]` — observing a failure * never destroys it. An * async branch is rejected at compile time ({@link NotThenable} on the * builder output) — other branch results are discarded, so a rejected * `Promise` would float unobserved. The * {@link AsyncResultMethods.tap | tap} fire-and-forget caveat applies here * too — a failable effect belongs in * {@link AsyncResultMethods.flatTapErrCases | flatTapErrCases}. */ tapErrCases(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => ExhaustiveMatch>): AsyncResult$1; /** * Asynchronous {@link ResultMethods.flatTapErrCases | flatTapErrCases} — the * error-channel mirror of `flatTap`. `f` may return a `Result` **or** an * `AsyncResult`; its `Ok` value is discarded, an `Err`/`Defect` from `f` * threads through, and if `f` throws — or a branch returns the injected * `defect(cause)` marker, the expression-position form of a throw — the result * is a `Defect` whose cause is an `AggregateError` of `[thrown, original * failure]` — observing a failure never destroys it. */ flatTapErrCases(f: (matcher: ErrMatcher, defect: (cause: unknown) => Defect) => ExhaustiveMatch | AsyncResult$1>): AsyncResult$1; /** * Asynchronous {@link ResultMethods.recoverDefect | recoverDefect}. `f` may * return a `Result` or an `AsyncResult`. */ recoverDefect(f: (cause: unknown) => Result$1 | AsyncResult$1): AsyncResult$1; /** * Asynchronous {@link ResultMethods.tapDefect | tapDefect}. If `f` throws, the * result is a `Defect` whose cause is an `AggregateError` of `[thrown, * original failure]` — observing a failure never destroys it. An async * callback is rejected at compile time ({@link NotThenable}). */ tapDefect(f: (cause: unknown) => R & NotThenable): AsyncResult$1; /** * Asynchronous {@link ResultMethods.tapFailure | tapFailure} — the * cross-channel observer. `f` receives the narrowed failure variant * ({@link FailureView}); if it throws, the result is a `Defect` whose cause * is an `AggregateError` of `[thrown, original failure]` — observing a * failure never destroys it. An async callback is rejected at compile time * ({@link NotThenable}). */ tapFailure(f: (failure: FailureView) => R & NotThenable): AsyncResult$1; /** * Asynchronous {@link ResultMethods.match | match}. Handlers are synchronous * (the `errCases` handler returns an exhaustive {@link ErrMatcher} builder, no * `defect` helper); resolves to a `Promise` of the folded value. */ match>(cases: { ok: (value: T) => ROk; errCases: (matcher: ErrMatcher) => M; defect: (cause: unknown) => RDefect; }): Promise>; /** * Asynchronous {@link ResultMethods.get | get}. Compiles only when the * error channel is empty (`this: AsyncResult`); the returned promise * rejects on a `Defect` (rethrowing its cause). */ get(this: AsyncResult$1): Promise; /** * Asynchronous {@link ResultMethods.getErr | getErr}. Compiles only when * the success channel is empty (`this: AsyncResult`); the returned * promise rejects on a `Defect` (rethrowing its cause). */ getErr(this: AsyncResult$1): Promise; /** Asynchronous {@link ResultMethods.getOr | getOr}. */ getOr(fallback: U): Promise; /** Asynchronous {@link ResultMethods.getOrElse | getOrElse}. */ getOrElse(f: (error: E) => U): Promise; /** Asynchronous {@link ResultMethods.getOrNull | getOrNull}. */ getOrNull(): Promise; /** Asynchronous {@link ResultMethods.getOrUndefined | getOrUndefined}. */ getOrUndefined(): Promise; /** * Asynchronous {@link ResultMethods.getOrThrow | getOrThrow} — the returned * promise **rejects** with the modeled error on `Err` (or the original cause * on a `Defect`), rather than throwing synchronously. Gated the same way: it * compiles only when the error channel is non-empty (`E` is not `never`). */ getOrThrow(this: [E] extends [never] ? "unthrown: getOrThrow is unnecessary here — the Err channel is empty (E = never), so there is nothing to throw. Use get() instead." : AsyncResult$1): Promise; }; /** * The asynchronous counterpart of {@link Result}: an awaitable wrapper carrying * the {@link AsyncResultMethods} surface, collapsing to a `Result` when * `await`-ed. * * @remarks * **Combinator callbacks are synchronous.** A raw `Promise` may never enter an * `AsyncResult` method — that would be an un-qualified async boundary, and its * rejection would silently become a `Defect`, skipping the triage that * {@link fromPromise} forces. To do further async work, re-enter through a * qualified boundary and compose it: `ar.flatMap((v) => fromPromise(work(v), * qualify))`. The eliminators (`get`, …) return promises; the binds * (`flatMap`, `flatTap`, `flatMapErrCases`, `recoverDefect`) additionally accept an * `AsyncResult`. Its combinators are documented one per entry on * {@link AsyncResultMethods}. * * To pattern-match an `AsyncResult`, `await` it first: `match(await ar)`. * * @typeParam T - the success value type. * @typeParam E - the modeled error type. */ interface AsyncResult$1 extends Awaitable>, AsyncResultMethods {} /** * Extract the success type `T` from a `Result` type — derive one type from * another instead of restating it (e.g. the payload a function returns). * * @typeParam R - the `Result` type to inspect. * * @example * ```ts * type R = Result; * type U = OkOf; // User * type E = ErrOf; // NotFound * ``` * * @category Types */ type OkOf = R extends { readonly tag: "Ok"; readonly value: infer T; } ? T : never; /** * Extract the error type `E` from a `Result` type — the counterpart of * {@link OkOf}. * * @typeParam R - the `Result` type to inspect. * * @example * ```ts * type E = ErrOf>; // NotFound * ``` * * @category Types */ type ErrOf = R extends { readonly tag: "Err"; readonly error: infer E; } ? E : never; /** * Extract the success type `T` from an {@link AsyncResult} type — the async * counterpart of {@link OkOf}. * * @typeParam R - the `AsyncResult` type to inspect. * * @example * ```ts * type T = AsyncOkOf>; // User * ``` * * @category Types */ type AsyncOkOf = R extends Awaitable ? OkOf : never; /** * Extract the error type `E` from an {@link AsyncResult} type — the async * counterpart of {@link ErrOf}. * * @typeParam R - the `AsyncResult` type to inspect. * * @example * ```ts * type E = AsyncErrOf>; // NotFound * ``` * * @category Types */ type AsyncErrOf = R extends Awaitable ? ErrOf : never; //#endregion //#region src/constructors.d.ts /** * Construct a successful `void` {@link Result} — `Result` — * sparing you `Ok(undefined)` and typing the success channel `void`, not * `undefined`. * * @example * ```ts * import { Ok } from "unthrown"; * * Ok(); // => a void success: Result * ``` * * @category Constructors */ declare function Ok(): Result$1; /** * Construct a successful {@link Result}. * * @typeParam T - the success value type. * @param value - the success value to wrap. * * @example * ```ts * import { Ok } from "unthrown"; * * Ok(2).map((n) => n + 1); // => Ok(3) * Ok(42).get(); // => 42 * ``` * * @category Constructors */ declare function Ok(value: T): Result$1; /** * Construct a failed {@link Result} carrying a **modeled** error. * * @typeParam E - the modeled error type. * @param error - the domain error to wrap. * * @example * ```ts * import { Err } from "unthrown"; * * Err("not_found").map((n) => n + 1); // => Err("not_found") (map skipped) * Err("not_found").getErr(); // => "not_found" * ``` * * @category Constructors */ declare function Err(error: E): Result$1; /** * Construct a successful `void` {@link AsyncResult} — `AsyncResult` * — the pre-lifted form of the no-arg {@link Ok}, sparing you * `Ok(undefined).toAsync()`. * * @example * ```ts * import { OkAsync } from "unthrown"; * * OkAsync(); // => a void success: AsyncResult * ``` * * @category Constructors */ declare function OkAsync(): AsyncResult$1; /** * Construct a successful {@link AsyncResult} from a pure value — the pre-lifted * form of {@link Ok}, sparing you `Ok(value).toAsync()`. * * @remarks * Reach for this on the synchronous/early branch of an `AsyncResult`-returning * function, so both branches share one return type without a trailing * `.toAsync()`. Named with the `Async` suffix the async free functions carry * (`allAsync`, `allFromDictAsync`); the {@link AsyncResult} companion aliases it * as `AsyncResult.Ok` (the namespace already says "async", so the suffix drops). * * @typeParam T - the success value type. * @param value - the success value to wrap. * * @example * ```ts * import { OkAsync, type AsyncResult } from "unthrown"; * * function loadItems(ids: string[]): AsyncResult { * if (ids.length === 0) return OkAsync([]); // no more Ok([]).toAsync() * return itemRepository.load(ids); * } * ``` * * @category Constructors */ declare function OkAsync(value: T): AsyncResult$1; /** * Construct a failed {@link AsyncResult} carrying a **modeled** error — the * pre-lifted form of {@link Err}, sparing you `Err(error).toAsync()`. * * @remarks * The error-channel mirror of {@link OkAsync}; see it for the naming and the * `AsyncResult.Err` companion alias. * * @typeParam E - the modeled error type. * @param error - the domain error to wrap. * * @example * ```ts * import { ErrAsync } from "unthrown"; * * ErrAsync("not_found"); // AsyncResult * ``` * * @category Constructors */ declare function ErrAsync(error: E): AsyncResult$1; /** * Type guard: narrow a {@link Result} to its `Ok` variant, exposing `.value`. * * @returns `true` when `r` is `Ok`. * * @example * ```ts * import { isOk, Ok, Err, type Result } from "unthrown"; * * isOk(Ok(1)); // => true * isOk(Err("boom")); // => false * * declare const r: Result; * if (isOk(r)) r.value; // number, narrowed * ``` * * @category Guards */ declare function isOk(r: Result$1): r is OkView; /** * Type guard: narrow a {@link Result} to its `Err` variant, exposing `.error`. * * @returns `true` when `r` is `Err`. * * @example * ```ts * import { isErr, Ok, Err, type Result } from "unthrown"; * * isErr(Err("boom")); // => true * isErr(Ok(1)); // => false * * declare const r: Result; * if (isErr(r)) r.error; // string, narrowed * ``` * * @category Guards */ declare function isErr(r: Result$1): r is ErrView; /** * Type guard: narrow a {@link Result} to its `Defect` variant, exposing `.cause`. * * @remarks * A `Defect` has no public constructor — it only arises at a boundary (e.g. a * callback throwing inside a combinator). This guard is how you detect one. * * @returns `true` when `r` is a `Defect`. * * @example * ```ts * import { isDefect, Ok } from "unthrown"; * * // A throw inside a combinator is captured as a Defect: * const r = Ok(1).map(() => { * throw new Error("boom"); * }); * isDefect(r); // => true * isDefect(Ok(1)); // => false * * if (isDefect(r)) r.cause; // unknown, narrowed * ``` * * @category Guards */ declare function isDefect(r: Result$1): r is DefectView; //#endregion //#region src/core.d.ts /** * Thrown by a {@link Result}'s `get` / `getErr` when the assertion is * wrong on a *modeled* result — `get()` on an `Err`, or `getErr()` on an * `Ok`. * * @remarks * The offending value is exposed two ways: the typed {@link GetError.error} * property for programmatic access, and the standard `Error.cause` for the * runtime and devtools to chain — when `E` is an `Error` (e.g. a `TaggedError`) * its original stack is printed under "caused by". * * A `Defect` is never wrapped in a `GetError`: its original cause is * re-thrown (with its original stack) instead. * * `get()` and `getErr()` are type-gated (`this: Result` / * `Result`), so the wrong-variant branch that throws this is * unreachable through well-typed code — it remains only as a defensive guard * against unsound runtime misuse (e.g. an `as` cast past the gate). * * @typeParam E - the type of the {@link GetError.error} it carries. * * @category Errors */ declare class GetError extends Error { /** * The offending value: the `Err` error for `get()`, or the `Ok` value for * `getErr()`. */ readonly error: E; constructor(error: E); } /** * Type guard: is `x` a {@link Result} (any of `Ok` / `Err` / `Defect`)? * * @remarks * Unlike {@link isOk} / {@link isErr} / {@link isDefect}, which narrow a value * already known to be a `Result`, this narrows from `unknown` — useful at an * untyped boundary. It checks the value carries the `Result` prototype * (`instanceof` first, falling back to the `Symbol.for("unthrown.Result")` * brand the prototype carries — so a `Result` built by **another copy** of * unthrown, e.g. the CJS and ESM builds loaded side by side, is still * recognised). A look-alike plain object (`{ tag: "Ok" }`) carries neither and * is **not** matched. An `AsyncResult` is not a `Result` and returns `false`. * * @returns `true` when `x` is a `Result` produced by this library. * * @example * ```ts * import { isResult, Ok, P } from "unthrown"; * * isResult(Ok(1)); // => true * isResult({ tag: "Ok" }); // => false (look-alike, wrong prototype) * isResult(Ok(1).toAsync()); // => false (an AsyncResult is not a Result) * * const x: unknown = Ok(1); * if (isResult(x)) * // `E` is `unknown` here — an untyped boundary has no cases to enumerate, * // so the `P._` escape hatch is the only arm that can terminate the match: * // oxlint-disable-next-line unthrown/no-catch-all-pattern -- untyped boundary: `E` is `unknown` * x.match({ * ok: () => 1, * errCases: (m) => m.with(P._, () => 0), * defect: () => -1, * }); * ``` * * @category Guards */ declare function isResult(x: unknown): x is Result$1; //#endregion //#region src/do.d.ts /** * Start a do-notation chain with an empty object scope, grown step by step with * `bind` (for `Result`-returning steps) and `let` (for pure values). * * @remarks * Capitalised because `do` is a reserved word. Each step receives the scope * accumulated so far; the error types union across `bind`s, and a throw in any * step becomes a `Defect`. To go asynchronous, lift the chain with `toAsync()` * (then a `bind` may return an `AsyncResult`). * * @example * ```ts * import { Do, Ok } from "unthrown"; * * const result = Do() * .bind("user", () => findUser(id)) // Result * .bind("org", ({ user }) => findOrg(user.orgId)) // Result * .let("label", ({ user, org }) => `${user.name} @ ${org.name}`) * .map(({ user, org, label }) => render(user, org, label)); * // Result * ``` * * @example * ```ts * import { Do, Ok, Err } from "unthrown"; * * // Ok path — the scope accumulates: * Do() * .bind("a", () => Ok(2)) * .let("b", ({ a }) => a * 10) * .map(({ a, b }) => a + b); // => Ok(22) * * // Err path — the first Err short-circuits the rest: * Do() * .bind("a", () => Err("boom")) * .let("b", ({ a }) => a); // => Err("boom") * ``` * * @category Do-notation */ declare function Do(): Result$1<{}, never>; /** * Start an **asynchronous** do-notation chain with an empty object scope — the * pre-lifted form of {@link Do}, sparing you `Do().toAsync()`. * * @remarks * From here a `bind` may return a `Result` **or** an `AsyncResult`; the scope * accumulates exactly as in a sync {@link Do} chain, and a throw in any step * becomes a `Defect`. Named with the `Async` suffix the async free functions * carry (`OkAsync`, `allAsync`); the {@link AsyncResult} companion aliases it as * `AsyncResult.Do` (the namespace already says "async", so the suffix drops). * * @example * ```ts * import { DoAsync, Ok } from "unthrown"; * * const result = await DoAsync() * .bind("user", () => findUser(id)) // AsyncResult * .bind("plan", ({ user }) => Ok(user.plan)) // a sync Result is accepted too * .let("label", ({ user, plan }) => `${user.name} on ${plan}`); * // Result<{ user: User; plan: Plan; label: string }, NotFound> * ``` * * @category Do-notation */ declare function DoAsync(): AsyncResult$1<{}, never>; //#endregion //#region src/interop.d.ts /** * Bridge a nullable value into a {@link Result}: absence becomes a **modeled** * `Err`. The sanctioned alternative to an `Option` type. * * @remarks * `null` and `undefined` map to `Err(onAbsent())`; any other value (including * falsy ones like `0`, `""`, `false`) maps to `Ok`. * * @typeParam T - the (nullable) value type. * @typeParam E - the error produced when the value is absent. * @param value - the possibly-absent value. * @param onAbsent - lazily produces the error for the absent case. * * @category Interop * * @example * ```ts * import { fromNullable } from "unthrown"; * * const map = new Map([["a", 1]]); * fromNullable(map.get("a"), () => "absent").getOr(0); // => 1 * fromNullable(map.get("z"), () => "absent"); // => Err("absent") * fromNullable(0, () => "absent").getOr(-1); // => 0 (falsy but present) * ``` */ declare function fromNullable(value: T | null | undefined, onAbsent: () => E): Result$1, E>; /** * Wrap a throwing synchronous function so it returns a {@link Result} instead of * throwing. * * @remarks * `qualify` **must** triage every thrown cause into a modeled error `E` or a * `Defect` (via the injected `defect` helper, its second argument) — there is no * path that leaves `unknown` in `E`. A throw inside `qualify` itself is treated * as a `Defect`. `qualify` is **synchronous**: an `async` qualify is rejected at * compile time ({@link NotThenable}) — its `Promise` would land in `E` un-triaged * — and a thenable slipped past the types at runtime becomes a `Defect` (never * an `Err(Promise)`), its orphaned rejection silenced. * * `fn` is **synchronous** too. An `async` `fn` rejects *after* this boundary has * already returned, so its rejection could never reach `qualify`: it becomes a * `Defect` (never `Ok()`) and the orphaned rejection is silenced rather * than left to float. Reach for {@link fromPromise} to wrap async work. * * The modeled error type is `Exclude` — the `Defect` arm of * `qualify`'s return is **subtracted** from `E`, never inferred into it. So a * `qualify` that returns *only* `defect(cause)` yields `E = never` (a Defect is * out-of-band and must not pollute the error channel); reach for * {@link fromSafeThrowable} when every throw is a Defect. * * @typeParam A - the wrapped function's argument tuple. * @typeParam T - the wrapped function's return type. * @typeParam R - `qualify`'s return type; the modeled error `E` is * `Exclude` (its `Defect` arm, if any, is subtracted). * @param fn - the throwing function to wrap. * @param qualify - triages a thrown `cause` into a modeled `E`, or marks it * unmodeled by returning `defect(cause)` (the helper passed as its second arg). * @returns a function with the same arguments returning `Result`. * * @category Interop * * @example * ```ts * import { fromThrowable } from "unthrown"; * * // Model the parse failure as an `Err`, everything unexpected as a `Defect`. * const parse = fromThrowable( * (text: string) => JSON.parse(text) as unknown, * (cause, defect) => * cause instanceof SyntaxError ? ("invalid_json" as const) : defect(cause), * ); * * parse('{"ok":true}').getOr(null); // => { ok: true } * parse("nope"); // => Err("invalid_json") * ``` */ declare function fromThrowable(fn: (...args: A) => T, qualify: (cause: unknown, defect: (cause: unknown) => Defect) => R & NotThenable): (...args: A) => Result$1>; /** * Wrap a throwing synchronous function asserted **not** to fail in any modeled * way: any throw becomes a `Defect`. * * @remarks * The synchronous counterpart of {@link fromSafePromise}. Use it only when a * throw genuinely indicates a bug rather than an anticipated outcome — the * error channel is `never`, so there is nothing to triage; there is no * `qualify`. When some throws *are* anticipated, reach for * {@link fromThrowable} and triage them. * * `fn` is **synchronous**: an `async` `fn` becomes a `Defect` (never * `Ok()`), with its orphaned rejection silenced rather than left to * float. Reach for {@link fromSafePromise} to wrap async work. * * @typeParam A - the wrapped function's argument tuple. * @typeParam T - the wrapped function's return type. * @param fn - the throwing function to wrap. * @returns a function with the same arguments returning `Result`. * * @category Interop * * @example * ```ts * import { fromSafeThrowable } from "unthrown"; * * // A decode failure here is a bug (the row came from our own schema), so * // every throw is a defect — no throwaway `(cause, defect) => defect(cause)`. * const decode = fromSafeThrowable((row: Row) => userSchema.parse(row)); * * decode(row); // => Result — a throw becomes a Defect * ``` */ declare function fromSafeThrowable(fn: (...args: A) => T): (...args: A) => Result$1; /** * Wrap a `Promise` (or a thunk producing one) as an {@link AsyncResult}, forcing * every rejection to be triaged. * * @remarks * `qualify` **must** map each rejection cause into a modeled error `E` or a * `Defect` (via the injected `defect` helper, its second argument). The returned * `AsyncResult`'s internal promise never rejects; `await`-ing it always yields a * `Result`. A throw inside `qualify` is itself a `Defect`. `qualify` is * **synchronous**: an `async` qualify is rejected at compile time * ({@link NotThenable}), and a thenable slipped past the types at runtime * becomes a `Defect` (never an `Err(Promise)`), its orphaned rejection silenced. * * The modeled error type is `Exclude` — the `Defect` arm of * `qualify`'s return is **subtracted** from `E`, never inferred into it. So a * `qualify` that returns *only* `defect(cause)` yields `E = never`; when every * rejection is a Defect, prefer {@link fromSafePromise}. * * @typeParam T - the resolved value type. * @typeParam R - `qualify`'s return type; the modeled error `E` is * `Exclude` (its `Defect` arm, if any, is subtracted). * @param promise - the promise, or a thunk returning one. * @param qualify - triages a rejection `cause` into a modeled `E`, or marks it * unmodeled by returning `defect(cause)` (the helper passed as its second arg). * @param _guard - compile-time only; never pass it. The phantom rest-tuple that * enforces "qualify is synchronous": an `async` qualify makes this demand an * impossible extra argument (whose type spells out the error), while a * synchronous one leaves it empty. Encoded here — not on `qualify`'s return * type — so `T`'s inference from `promise` is undisturbed. * * @category Interop * * @example * ```ts * import { fromPromise } from "unthrown"; * * // A rejection with a NotFoundError becomes a modeled `Err`; anything else a Defect. * const user = await fromPromise(fetchUser(id), (cause, defect) => * cause instanceof NotFoundError ? ("not_found" as const) : defect(cause), * ); * * if (user.isOk()) user.value; // => the fetched user * // when fetchUser rejects with NotFoundError: user is Err("not_found") * ``` */ declare function fromPromise(promise: Promise | (() => Promise), qualify: (cause: unknown, defect: (cause: unknown) => Defect) => R, ..._guard: [Extract>] extends [never] ? [] : ["unthrown: qualify must be synchronous — its Promise would land in E un-triaged"]): AsyncResult$1>; /** * Wrap a `Promise` asserted **not** to fail in any modeled way: any rejection * becomes a `Defect`. * * @remarks * Use this only when a rejection genuinely indicates a bug rather than an * anticipated outcome — the error channel is `never`, so there is nothing to * triage. (`await`-ing still yields a `Result`; it never throws.) The * synchronous counterpart is {@link fromSafeThrowable}. * * @typeParam T - the resolved value type. * @param promise - the promise, or a thunk returning one. * * @category Interop * * @example * ```ts * import { fromSafePromise } from "unthrown"; * * (await fromSafePromise(Promise.resolve(3))).get(); // => 3 * // a rejection becomes a Defect (never a modeled Err): * await fromSafePromise(Promise.reject(new Error("boom"))); // => Defect(Error("boom")) * ``` */ declare function fromSafePromise(promise: Promise | (() => Promise)): AsyncResult$1; /** * The settler a {@link fromExecutor} executor receives. Settles the pending * `AsyncResult` **once** — later calls are no-ops, exactly as `resolve` is on a * `Promise`. * * @typeParam T - the success type. * @typeParam E - the modeled error type. * * @category Types */ type Settle = (result: Result$1 | Defect) => void; /** * Build an {@link AsyncResult} from a callback-style API — this library's * answer to `new Promise((resolve, reject) => …)`. * * @remarks * The settler takes a **`Result`**, not a value-or-reason pair: the caller names * the variant, so no `unknown` can enter `E` and there is no `qualify` to pass. * For a failure that is *not* modeled, settle the injected `defect` helper's * marker — the same injection `qualify` receives, and the only way to reach the * defect channel from inside an asynchronous callback (a `throw` there runs in * its own turn, long after the executor body returned). * * `T` and `E` cannot be inferred from the body, since `settle` is a parameter. * Supply them explicitly, or let them flow from an annotated target. Absent * either, both default to `never` (Thesis #3: no path may produce `unknown` in * `E`) — so an unannotated call is a compile error at the `settle(...)` call * site, not a silently-`unknown` channel. * * An executor that never settles yields an `AsyncResult` that never resolves — * the one hazard {@link fromPromise} does not have, and identical to * `new Promise`. * * @typeParam T - the success type. * @typeParam E - the modeled error type. * @param executor - runs immediately; receives the settler and the `defect` helper. * * @category Interop * * @example * ```ts * import { fromExecutor, Err, Ok } from "unthrown"; * * const listen = (port: number) => * fromExecutor((settle, defect) => { * server.once("error", (cause) => * isAddrInUse(cause) ? settle(Err(new PortInUse(port))) : settle(defect(cause)), * ); * server.listen(port, () => settle(Ok(server))); * }); * ``` */ declare function fromExecutor(executor: (settle: Settle, defect: (cause: unknown) => Defect) => void): AsyncResult$1; /** * The success channel of {@link all} / {@link allAsync}: a **positional tuple** * for a fixed-length input (including the empty tuple), or a homogeneous * **array** for a dynamic one. * * @remarks * The split keys off the input's `length`: a fixed tuple has a literal length * (`number extends Rs["length"]` is false → keep the positional `Ts`), while a * general array has `length: number` (→ collapse to `Ts[number][]`). Checking * length rather than `Rs extends [unknown, ...unknown[]]` keeps `all([])` typed * as `Result<[], …>` instead of `Result`. * * @typeParam Rs - the tuple/array of input `Result` types. * @typeParam Ts - per-element extracted success types (`OkOf` for `all`, * `AsyncOkOf` for `allAsync`). * @internal */ type AllOk = number extends Rs["length"] ? Ts[number][] : Ts; /** A record of `Result`s — the input to {@link allFromDict}. */ type ResultRecord = Record>; /** A record of `AsyncResult`s — the input to {@link allFromDictAsync}. */ type AsyncResultRecord = Record>; /** * Collect a tuple/array of {@link Result}s into a single `Result` of all their * success values. * * @remarks * Short-circuits on the **first** `Err` (later entries are not inspected for * their error); any `Defect` present **dominates**, winning even over an earlier * `Err`. A **fixed tuple** keeps its positional types — `all([Ok(1), Ok("a")])` * is `Result<[number, string], …>` — while a **dynamic array** `Result[]` * collapses to `Result` with no cast. For a **record** keyed by name, * use {@link allFromDict}. * * @category Aggregate * * @example * ```ts * import { all, Ok, Err } from "unthrown"; * * all([Ok(1), Ok("a"), Ok(true)]).get(); // => [1, "a", true] (typed [number, string, boolean]) * all([Ok(1), Err("e"), Ok(3)]); // => Err("e") (short-circuits on the first Err) * ``` */ declare function all[]>(results: readonly [...Rs]): Result$1; }>, ErrOf>; /** * Collect a **record** of {@link Result}s into a single `Result` of a record of * their success values — `allFromDict({ a: Result, b: Result })` is * `Result<{ a: A; b: B }, E>`. The named counterpart of {@link all}, for * parallel work you'd rather not tuple. * * @remarks * Same folding rules as {@link all}: first `Err` short-circuits, any `Defect` * dominates. This is **not** error accumulation. * * @category Aggregate * * @example * ```ts * import { allFromDict, Ok, Err } from "unthrown"; * * allFromDict({ id: Ok(1), name: Ok("ada") }).get(); // => { id: 1, name: "ada" } * allFromDict({ id: Ok(1), name: Err("missing") }); // => Err("missing") * ``` */ declare function allFromDict(results: R): Result$1<{ [K in keyof R]: OkOf; }, ErrOf>; /** * The asynchronous counterpart of {@link all}: combine a tuple/array of * {@link AsyncResult}s into one `AsyncResult` of all their success values. * * @remarks * The inputs are resolved **concurrently** (order preserved); the resolved * `Result`s are then folded with the same rules as {@link all} — first `Err` * short-circuits, any `Defect` dominates. As ever, the returned `AsyncResult`'s * internal promise never rejects. For a **record**, use {@link allFromDictAsync}. * * @category Aggregate * * @example * ```ts * import { allAsync, fromSafePromise } from "unthrown"; * * const both = allAsync([ * fromSafePromise(Promise.resolve(1)), * fromSafePromise(Promise.resolve(2)), * ]); * (await both).get(); // => [1, 2] * ``` */ declare function allAsync[]>(results: readonly [...Rs]): AsyncResult$1; }>, AsyncErrOf>; /** * The asynchronous counterpart of {@link allFromDict}: combine a record of * {@link AsyncResult}s into one `AsyncResult` of a record of their values. * * @remarks * Resolved concurrently (order preserved), folded with the {@link all} rules, * and the internal promise never rejects. * * @category Aggregate * * @example * ```ts * import { allFromDictAsync, fromSafePromise } from "unthrown"; * * const both = allFromDictAsync({ * a: fromSafePromise(Promise.resolve(1)), * b: fromSafePromise(Promise.resolve("x")), * }); * (await both).get(); // => { a: 1, b: "x" } * ``` */ declare function allFromDictAsync(results: R): AsyncResult$1<{ [K in keyof R]: AsyncOkOf; }, AsyncErrOf>; //#endregion //#region src/facade.d.ts /** * Companion object grouping the **`Result`-producing** entry points under a * single, discoverable namespace: {@link Result.Ok}, {@link Result.Err}, * {@link Result.Do}, {@link Result.fromNullable}, {@link Result.fromThrowable}, * {@link Result.fromSafeThrowable}, {@link Result.all}, * {@link Result.allFromDict}, {@link Result.isOk}, {@link Result.isErr}, * {@link Result.isDefect}, {@link Result.isResult}. * * @remarks * Purely additive sugar — each member **is** the corresponding free function. * The free functions remain the primary, tree-shakeable API; importing only * `{ Ok }` never pulls this object in. The value `Result` and the type * {@link Result} share one name (the companion-object pattern). * * The **async** entry points live on the sibling {@link AsyncResult} companion * (`AsyncResult.fromPromise`, `AsyncResult.all`, …), grouped by what they * return — a static lives in exactly one namespace. * * @category Facade * * @example * ```ts * import { Result } from "unthrown"; * Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).get(); // => 2 * ``` */ declare const Result: { readonly Ok: typeof Ok; readonly Err: typeof Err; readonly Do: typeof Do; readonly fromNullable: typeof fromNullable; readonly fromThrowable: typeof fromThrowable; readonly fromSafeThrowable: typeof fromSafeThrowable; readonly all: typeof all; readonly allFromDict: typeof allFromDict; readonly isOk: typeof isOk; readonly isErr: typeof isErr; readonly isDefect: typeof isDefect; readonly isResult: typeof isResult; }; /** * `Result` — the core discriminated union. Shares its name with the * {@link Result | companion object} above (the value and type are one name); this * is the type half. * * @remarks * A `Result` is a discriminated union, so TypeDoc can't list its methods on this * alias. Its fluent combinators (`map`, `flatMap`, `match`, `get`, …) are * documented one per entry on {@link ResultMethods} — the shared method surface * every variant carries. For "which one do I reach for?", see the * [Choosing a combinator](/reference/combinators) guide. * * @category Facade */ type Result = Result$1; /** * Companion object grouping the **`AsyncResult`-producing** entry points under * the matching namespace: {@link AsyncResult.Ok}, {@link AsyncResult.Err}, * {@link AsyncResult.Do}, {@link AsyncResult.fromExecutor}, * {@link AsyncResult.fromPromise}, {@link AsyncResult.fromSafePromise}, * {@link AsyncResult.all}, {@link AsyncResult.allFromDict}. * * @remarks * The async sibling of {@link Result}. Statics are grouped by what they * **return**, so the pre-lifted constructors, `fromExecutor`, * `fromPromise`/`fromSafePromise`, and the async aggregates sit here rather * than on {@link Result}; the namespace * already conveys "async", so the members drop the `Async` suffix their free * functions carry (`AsyncResult.Ok` is `OkAsync`; `AsyncResult.Err` is * `ErrAsync`; `AsyncResult.Do` is `DoAsync`; `AsyncResult.all` is `allAsync`; * `AsyncResult.allFromDict` is * `allFromDictAsync`). Like {@link Result}, the free functions remain the * primary, tree-shakeable API; the value `AsyncResult` and the type * {@link AsyncResult} share one name. * * @category Facade * * @example * ```ts * import { AsyncResult } from "unthrown"; * const user = await AsyncResult.fromPromise( * fetchUser(id), * (c, defect) => defect(c), * ); * user.get(); // => the fetched user (on success) * ``` */ declare const AsyncResult: { readonly Ok: typeof OkAsync; readonly Err: typeof ErrAsync; readonly Do: typeof DoAsync; readonly fromExecutor: typeof fromExecutor; readonly fromPromise: typeof fromPromise; readonly fromSafePromise: typeof fromSafePromise; readonly all: typeof allAsync; readonly allFromDict: typeof allFromDictAsync; }; /** * `AsyncResult` — the async counterpart of {@link Result}. Shares its name * with the {@link AsyncResult | companion object} above (value and type are one * name); this is the type half. * * @remarks * `AsyncResult` carries the async fluent surface; its combinators (`map`, * `flatMap`, `match`, `get`, …) are documented one per entry — with their * async signatures — on {@link AsyncResultMethods}. For "which one do I reach * for?", see the [Choosing a combinator](/reference/combinators) guide. * * @category Facade */ type AsyncResult = AsyncResult$1; //#endregion //#region src/tagged.d.ts type Props = Record; /** * The instance shape produced by a {@link TaggedError} class: an `Error` plus a * `_tag` discriminant and the (readonly) payload fields. * * @typeParam Tag - the string literal discriminant. * @typeParam A - the payload object type. * * @category Types */ type TaggedErrorInstance = Error & Readonly> & { readonly _tag: Tag; }; /** * The class constructor returned by {@link TaggedError}. Generic in its payload: * apply it with an instantiation expression at the `extends` site. * * @remarks * When the payload is empty, the constructor takes **no** arguments (the * `keyof A extends never ? void : A` trick); otherwise it takes the payload. The * `name`, `message`, and `stack` keys are all **rejected** (`?: never`) because * all three are reserved: `name` is the display label, `message` is the human * string owned by `Error`, and `stack` is `Error`'s trace. Set the message the * standard way — `override message = "…"` (or a constructor override) on the * subclass — never as a free-form per-call payload field. The reservations are * enforced at the call site, mirroring how {@link TaggedErrorInstance} excludes * all three. (`cause` is deliberately **not** reserved: `Error.cause` is * `unknown`, so a typed payload `cause` is a legitimate structured field.) * * @typeParam Tag - the string literal discriminant. * * @category Types */ type TaggedErrorConstructor = { new (args: keyof A extends never ? void : A & { readonly name?: never; readonly message?: never; readonly stack?: never; }): TaggedErrorInstance; }; /** * Build a base class for a tagged error — a class extending `Error` with a * `_tag` string discriminant, in the style of Effect's `Data.TaggedError`. * * @remarks * Extend the returned class to declare a concrete error. Supply the payload with * an instantiation expression; omit it for a payload-less error. The `message` * is **not** a payload field — it is the human string owned by `Error`, not * structured data, so it is reserved. Define it once per subclass the standard * way, `override message = "…"` (it may interpolate the payload via `this`, * which the base populates before the subclass field initialiser runs); a * payload `message` is rejected at compile time, so contextual detail lives in * typed fields, never baked into per-call prose. The `_tag` always reflects * `tag` and cannot be overridden by the payload. `name` is likewise reserved — * it is the display label (set it with `options.name`); a payload `name` is * rejected at compile time (and excluded from the instance type), so it can't * shadow `Error.name`. `stack` is reserved the same way — it is `Error`'s * trace, and even an untyped payload `stack` cannot clobber the real one. * `cause` is deliberately **not** reserved: `Error.cause` is typed `unknown`, * so a payload `cause` (e.g. a wrapped driver error) is a legitimate, * *narrowing* structured field. * * The matching half of the convention is `P.tag(t)` — the pattern constructor on * the `P` namespace, which builds the `{ _tag: t }` pattern this factory's `_tag` * is selected by (there is no standalone `tag` export). * * `_tag` is the discriminant matched by `P.tag` in the error combinators * (`result.mapErrCases((matcher) => matcher.with(P.tag("NotFound"), …))`) and in * `match`'s `errCases` handler; `Error.name` is the human-facing label in stack * traces and logs. By default they coincide, but * they can be **decoupled** with `options.name` — so a tag can be namespaced for * collision-safety (`"@my-lib/RetryableError"`) without that slash-prefixed * string leaking into `Error.name`: * * ```ts * class RetryableError extends TaggedError("@my-lib/RetryableError", { * name: "RetryableError", * }) { * override message = "operation failed; safe to retry"; * } * * const e = new RetryableError(); * e._tag; // "@my-lib/RetryableError" — namespaced discriminant * e.name; // "RetryableError" — clean display name * e.message; // "operation failed; safe to retry" — the standard Error.message * ``` * * @typeParam Tag - the string literal discriminant. * @param tag - the discriminant value; also the default error `name`. * @param options - optional overrides. `options.name` sets `Error.name` * independently of `tag` (defaults to `tag`). * * @category Tagged errors * * @example * ```ts * class NotFound extends TaggedError("NotFound") {} * class HttpError extends TaggedError("HttpError")<{ status: number }> {} * * new NotFound()._tag; // => "NotFound" * new HttpError({ status: 500 }).status; // => 500 * ``` */ declare function TaggedError(tag: Tag, options?: { readonly name?: string; }): TaggedErrorConstructor; //#endregion export { type AsyncErrOf, type AsyncOkOf, AsyncResult, type AsyncResultMethods, type Awaitable, type DefectView, Do, DoAsync, Err, ErrAsync, type ErrMatcher, type ErrOf, type ErrView, type FailureView, GetError, type Matcher, NonExhaustiveError, type NotThenable, Ok, OkAsync, type OkOf, type OkView, P, type PatternMatcher, Result, type ResultMethods, type Settle, TaggedError, type TaggedErrorConstructor, type TaggedErrorInstance, type UniversalPattern, all, allAsync, allFromDict, allFromDictAsync, fromExecutor, fromNullable, fromPromise, fromSafePromise, fromSafeThrowable, fromThrowable, isDefect, isErr, isOk, isResult, match };