Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions .changeset/document-combinator-surface.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
---
"unthrown": minor
"unthrown": patch
---

Make the fluent combinator surface (`map`, `flatMap`, `bind`, `match`, `unwrap`,
…) show up in the generated API reference. The methods were authored on an
internal `ResultMethods` type that TypeDoc dropped, so a discriminated-union
alias like `Result`/`AsyncResult` carried no method list anywhere in the docs.
Make the fluent combinators discoverable in the generated API reference. Because
`Result` / `AsyncResult` are discriminated-union aliases, TypeDoc can't list
their methods on the type page. Rather than expose a standalone method-surface
type for that (which would split the docs into two near-duplicate blocks), the
`Result` / `AsyncResult` type docs now link to the intent-organized "Choosing a
combinator" guide, which covers both in one shared table. The core
`typedoc.json` also gets an explicit `categoryOrder` (`Facade` → `Types` →
`Constructors` → … then `Aggregate`, `Errors`) so the core surface leads the
reference instead of the default alphabetical order, which had buried it under
`Aggregate`.

`ResultMethods<T, E>` and the new parallel `AsyncResultMethods<T, E>` are now
**exported** and documented under the `Types` category (they are the single home
a union alias can hang its method list on); the `Result`/`AsyncResult` type docs
`{@link}` them. The core API reference also gets an explicit `categoryOrder`
(`Facade` → `Types` → `Constructors` → … then `Aggregate`, `Errors`) so the core
surface leads instead of the default alphabetical order, which had buried it
under `Aggregate`.
The `ResultMethods` / `AsyncResultMethods` types stay **internal** — not part of
the public API. (An earlier, still-unreleased change briefly exported them; this
removes those exports before any release, so no published type surface changes.)
25 changes: 15 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,21 @@ async work re-enters via `fromPromise` / `fromSafePromise` and composes with
styles — not a second concept. (Each companion re-aliases its type in
`facade.ts`, so the `types.ts` `Result`/`AsyncResult` declarations both sit in
`typedoc.json`'s `intentionallyNotExported`.)
- method surface: the fluent combinators live on **`ResultMethods<T, E>`** (and
its async twin **`AsyncResultMethods<T, E>`**) — the object-literal types each
`Result` / `AsyncResult` variant intersects. Both are **exported from
`index.ts`** and carry `@category Types`: a discriminated union alias can't hang
a method list off itself in TypeDoc, so these named types are the single
documented home for `map`/`flatMap`/`match`/… (the `Result` / `AsyncResult` doc
comments `{@link}` them). The core `typedoc.json` sets an explicit
`categoryOrder` (`Facade`, `Types`, `Constructors`, … then `Aggregate`,
`Errors`) so the core surface leads the API reference instead of the default
alphabetical order (which buried it under `Aggregate`).
- method surface: the fluent combinators live on the **internal**
`ResultMethods<T, E>` — the object-literal type each `Result` variant
intersects (`@internal`, in `typedoc.json`'s `intentionallyNotExported`). It is
**deliberately not a public/exported type**: a `Result` is a discriminated
union, and a union alias can't hang a method list off itself in TypeDoc, so
exposing `ResultMethods` (plus an async twin) would just split the surface into
two near-duplicate, off-to-the-side method blocks. Instead the combinators are
documented **by intent** — one table covering both `Result` and `AsyncResult` —
in the `docs/guide/choosing-a-combinator.md` guide, which the generated
`Result` / `AsyncResult` type docs link to (a root-relative
`/guide/choosing-a-combinator` markdown link, base-prefixed by
VitePress). The core `typedoc.json` also sets an explicit `categoryOrder`
(`Facade`, `Types`, `Constructors`, … then `Aggregate`, `Errors`) so the core
surface leads the API reference instead of the default alphabetical order
(which buried it under `Aggregate`).
- tagged errors: `TaggedError(tag, options?)` (the error-class factory; optional
`options.name` sets `Error.name` independently of the `_tag` discriminant, so a
tag can be namespaced for collision-safety without leaking into the display
Expand Down
11 changes: 7 additions & 4 deletions packages/core/src/facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ export const Result = {
* is the type half.
*
* @remarks
* The fluent combinators (`map`, `flatMap`, `match`, `unwrap`, …) every variant
* carries are documented on {@link ResultMethods}.
* A `Result` is a discriminated union, so its fluent combinators (`map`,
* `flatMap`, `match`, `unwrap`, …) aren't listed as a standalone type here; they
* are documented by intent — with the same surface shared by `AsyncResult` — in
* the [Choosing a combinator](/guide/choosing-a-combinator) guide.
*
* @category Facade
*/
Expand Down Expand Up @@ -111,8 +113,9 @@ export const AsyncResult = {
* name); this is the type half.
*
* @remarks
* The fluent combinators it carries are documented on
* {@link AsyncResultMethods}.
* `AsyncResult` shares `Result`'s fluent surface (`map`, `flatMap`, `match`, …);
* those combinators are documented by intent in the
* [Choosing a combinator](/guide/choosing-a-combinator) guide.
*
* @category Facade
*/
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ export type { TaggedErrorConstructor, TaggedErrorInstance, TagHandlers } from ".
export type {
AsyncErrOf,
AsyncOkOf,
AsyncResultMethods,
Awaitable,
DefectView,
ErrOf,
ErrView,
OkOf,
OkView,
ResultMethods,
} from "./types.js";
31 changes: 7 additions & 24 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ export type Prettify<T> = { [K in keyof T]: T[K] } & {};
export type Bound<T, K extends string, U> = Prettify<Omit<T, K> & { readonly [P in K]: U }>;

/**
* The fluent method surface every {@link Result} variant carries. Factored out
* so the three variants ({@link OkView}, {@link ErrView}, {@link DefectView}) can
* each intersect it — and so the combinators (`map`, `flatMap`, `match`, …) have
* a single documented home, since a discriminated union can't carry a method
* list on its own. The async counterpart is {@link AsyncResultMethods}.
* The method surface every {@link Result} variant carries. Factored out so the
* three variants ({@link OkView}, {@link ErrView}, {@link DefectView}) can each
* intersect it. Not part of the public API on its own — a `Result` is a
* discriminated union, so its combinators are documented by intent in the
* "Choosing a combinator" guide rather than as a standalone type here.
*
* @typeParam T - the success value type.
* @typeParam E - the modeled error type.
* @category Types
* @internal
*/
export type ResultMethods<T, E> = {
/**
Expand Down Expand Up @@ -401,24 +401,7 @@ export type Awaitable<T> = {
* @typeParam T - the success value type.
* @typeParam E - the modeled error type.
*/
export type AsyncResult<T, E> = Awaitable<Result<T, E>> & AsyncResultMethods<T, E>;

/**
* The fluent method surface an {@link AsyncResult} carries — the async
* counterpart of {@link ResultMethods}, factored out so the combinators have a
* single documented home (an {@link AsyncResult} is `Awaitable<Result>`
* intersected with these methods).
*
* @remarks
* **Combinator callbacks are synchronous** (see {@link AsyncResult}). The binds
* (`flatMap`, `flatTap`, `bind`, `orElse`, `recoverDefect`) additionally accept
* an `AsyncResult`; the eliminators (`unwrap`, …) return promises.
*
* @typeParam T - the success value type.
* @typeParam E - the modeled error type.
* @category Types
*/
export type AsyncResultMethods<T, E> = {
export type AsyncResult<T, E> = Awaitable<Result<T, E>> & {
/** Asynchronous `map`. `f` is synchronous; a throw becomes a `Defect`. */
map<U>(f: (value: T) => U): AsyncResult<U, E>;
/**
Expand Down
1 change: 1 addition & 0 deletions packages/core/typedoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"AsyncResult",
"Defect",
"Props",
"ResultMethods",
"AllOk",
"ResultRecord",
"AsyncResultRecord"
Expand Down
Loading