> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cbrock.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# ResultAsync

> The async counterpart to Result.

`ResultAsync<T, E>` is a `PromiseLike<Result<T, E>>`. You can `await` or `.then()` it directly to get a synchronous `Result<T, E>`, or chain methods on it without ever leaving the async context. Nearly Every method that exists on `Result` has an equivalent on `ResultAsync`, and each returns another `ResultAsync` so chains stay fluent.

```typescript theme={null}
import { chas } from 'ts-chas';

const result: chas.Result<number, string> = await chas.okAsync(42);
// Ok(42)
```

***

## Creating a `ResultAsync`

### `chas.okAsync(value)`

Wraps a value or `Promise<T>` in a `ResultAsync` that resolves to `Ok`.

<ParamField path="value" type="T | Promise<T>" required>
  The success value or promise to wrap.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T, never>">
  Resolves to `Ok(value)`.
</ResponseField>

```typescript theme={null}
const res = chas.okAsync(42);
const result = await res; // Ok(42)
```

***

### `chas.errAsync(error)`

Wraps an error or `Promise<E>` in a `ResultAsync` that resolves to `Err`.

<ParamField path="error" type="E | Promise<E>" required>
  The error value or promise to wrap.
</ParamField>

<ResponseField name="returns" type="ResultAsync<never, E>">
  Resolves to `Err(error)`.
</ResponseField>

```typescript theme={null}
const res = chas.errAsync('request failed');
const result = await res; // Err('request failed')
```

***

### `chas.fromPromise(promise, mapErr?)`

Wraps a native `Promise` in a `ResultAsync`. Resolves to `Ok` on fulfillment and `Err` on rejection.

<ParamField path="promise" type="Promise<T>" required>
  The promise to wrap.
</ParamField>

<ParamField path="mapErr" type="(error: unknown) => E">
  Maps the rejection reason to your error type. When omitted, the error is typed as `unknown`.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T, E>">
  A `ResultAsync` wrapping the promise outcome.
</ResponseField>

```typescript theme={null}
const res = chas.fromPromise(
  fetch('/api/user').then(r => r.json()),
  (e) => `Fetch failed: ${e}`
);
```

***

### `ResultAsync.fromResult(syncResult)`

Lifts a synchronous `Result` into `ResultAsync`.

<ParamField path="syncResult" type="Result<T, E>" required>
  The synchronous result to wrap.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T, E>">
  A `ResultAsync` that immediately resolves to the provided result.
</ResponseField>

```typescript theme={null}
const sync = chas.ok(42);
const async = chas.ResultAsync.fromResult(sync);
const result = await async; // Ok(42)
```

***

### `ResultAsync.fromSafePromise(promise)`

Wraps a promise that is guaranteed not to reject. No `mapErr` is needed.

<ParamField path="promise" type="Promise<T>" required>
  A promise that will not reject.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T, never>">
  Resolves to `Ok(value)`.
</ResponseField>

```typescript theme={null}
const res = chas.ResultAsync.fromSafePromise(Promise.resolve(42));
const result = await res; // Ok(42)
```

***

## Instance methods

All methods below return a `ResultAsync`, so you can chain them without `await` until you need the final value.

### `.map(fn)`

Transforms the `Ok` value. `Err` passes through unchanged.

<ParamField path="fn" type="(value: T) => U | Promise<U>" required>
  Function applied to the `Ok` value. May be async.
</ParamField>

<ResponseField name="returns" type="ResultAsync<U, E>">
  `Ok(fn(value))` or the original `Err`.
</ResponseField>

```typescript theme={null}
const res = chas.okAsync(5).map(v => v * 2);
const result = await res; // Ok(10)
```

***

### `.mapErr(fn)`

Transforms the `Err` error. `Ok` passes through unchanged.

<ParamField path="fn" type="(error: E) => F | Promise<F>" required>
  Function applied to the `Err` error. May be async.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T, F>">
  The original `Ok` or `Err(fn(error))`.
</ResponseField>

```typescript theme={null}
const res = chas.errAsync('not_found').mapErr(e => e.toUpperCase());
const result = await res; // Err('NOT_FOUND')
```

***

### `.andThen(fn)`

Chains another `Result`- or `ResultAsync`-returning function. Calls `fn` with the `Ok` value, or short-circuits on `Err`.

<ParamField path="fn" type="(value: T) => Result<U, F> | ResultAsync<U, F>" required>
  Function returning a new result. May return sync or async.
</ParamField>

<ResponseField name="returns" type="ResultAsync<U, E | F>">
  The chained result, or the original `Err`.
</ResponseField>

```typescript theme={null}
const res = chas.okAsync(5).andThen(v => chas.okAsync(v * 2));
const result = await res; // Ok(10)
```

***

### `.orElse(fn)`

Recovers from an `Err` by calling `fn` with the error. `Ok` passes through unchanged.

<ParamField path="fn" type="(error: E) => Result<T2, F> | ResultAsync<T2, F>" required>
  Recovery function returning a new result.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T | T2, F>">
  The original `Ok`, or the recovery result.
</ResponseField>

```typescript theme={null}
const res = chas.errAsync('timeout').orElse(() => chas.okAsync('default'));
const result = await res; // Ok('default')
```

***

### `.tap(fn)`

Runs a side effect when `Ok`. Returns the original result unchanged.

<ParamField path="fn" type="(value: T) => void | Promise<void>" required>
  Side-effect function. May be async.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T, E>">
  The original result, unmodified.
</ResponseField>

```typescript theme={null}
const res = await fetchUser()
  .tap(async u => await auditLog.record(u.id));
```

***

### `.tapErr(fn)`

Runs a side effect when `Err`. Returns the original result unchanged.

<ParamField path="fn" type="(error: E) => void | Promise<void>" required>
  Side-effect function. May be async.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T, E>">
  The original result, unmodified.
</ResponseField>

```typescript theme={null}
const res = await fetchUser()
  .tapErr(async e => await errorLog.send(e));
```

***

### `.match({ ok, err })`

Exhaustively handles both branches and resolves to a plain value.

<ParamField path="ok" type="(value: T) => U | Promise<U>" required>
  Handler called when the result is `Ok`.
</ParamField>

<ParamField path="err" type="(error: E) => F | Promise<F>" required>
  Handler called when the result is `Err`.
</ParamField>

<ResponseField name="returns" type="Promise<U | F>">
  A standard `Promise` (not a `ResultAsync`) resolving to the matched handler's return value.
</ResponseField>

```typescript theme={null}
const message = await chas.okAsync(42).match({
  ok: v => `Got ${v}`,
  err: e => `Failed: ${e}`,
});
// 'Got 42'
```

***

### `.unwrap()`

Returns a `Promise` that resolves to the `Ok` value, or throws the `Err` error.

<ResponseField name="returns" type="Promise<T>">
  Resolves to the `Ok` value.
</ResponseField>

<Warning>
  Throws the contained error if the result is `Err`. Prefer `.unwrapOr()` or `.match()` in production code.
</Warning>

```typescript theme={null}
const value = await chas.okAsync(5).unwrap(); // 5
```

***

### `.unwrapOr(defaultValue)`

Returns a `Promise` that resolves to the `Ok` value, or `defaultValue` if `Err`.

<ParamField path="defaultValue" type="T" required>
  Fallback value returned when the result is `Err`.
</ParamField>

<ResponseField name="returns" type="Promise<T>">
  Resolves to the `Ok` value or the default.
</ResponseField>

```typescript theme={null}
const value = await chas.errAsync('missing').unwrapOr(0); // 0
```

***

### `.pipe(fn1, fn2, ...)`

Passes the `ResultAsync` through a sequence of functions, identical in behaviour to `Result#pipe`.

```typescript theme={null}
const add5 = (r: chas.ResultAsync<number, never>) => r.map(v => v + 5);
const double = (r: chas.ResultAsync<number, never>) => r.map(v => v * 2);

const result = await chas.okAsync(1).pipe(add5, double);
// Ok(12)
```

***

### `.context(ctx)`

Attaches a debug label or metadata object to the error when `Err`. No-op when `Ok`.

<ParamField path="ctx" type="string | Record<string, unknown>" required>
  A description string or metadata object for the current step.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T, E>">
  The same result with context prepended to `error._context` (if `Err`).
</ResponseField>

```typescript theme={null}
const result = await fetchUser(id)
  .context('fetching user')
  .andThen(u => validatePermissions(u))
  .context('checking permissions');
```

***

### `.catchTag(target, handler)`

Catches a specific tagged error variant by `_tag` or error factory, and removes it from the error union. Unmatched tags pass through unchanged.

<ParamField path="target" type="string | ErrorFactory" required>
  The `_tag` string to match, or an error factory.
</ParamField>

<ParamField path="handler" type="(error: MatchedError) => Result<T2, E2> | ResultAsync<T2, E2>" required>
  Recovery function.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T | T2, Exclude<E, { _tag: ... }> | E2>">
  A result with the matched tag removed from the error union.
</ResponseField>

```typescript theme={null}
await fetchUser(id)
  .catchTag('NotFound', () => chas.ok(GUEST_USER));
// ResultAsync<User | GuestUser, Unauthorized>
```

***

### `.tapTag(target, handler)`

Runs a side effect for a specific tagged error. The original result is returned unchanged.

<ParamField path="target" type="string | ErrorFactory" required>
  The `_tag` string to match, or an error factory.
</ParamField>

<ParamField path="handler" type="(error: MatchedError) => void | Promise<void>" required>
  Side-effect function called when the tag matches.
</ParamField>

<ResponseField name="returns" type="ResultAsync<T, E>">
  The original result, unmodified.
</ResponseField>

```typescript theme={null}
await fetchUser(id)
  .tapTag('Unauthorized', () => redirectToLogin());
```

***

## Complete example

```typescript theme={null}
import { chas } from 'ts-chas';

interface User { id: number; name: string }

function fetchUser(id: number): chas.ResultAsync<User, string> {
  return chas.fromPromise(
    fetch(`/api/users/${id}`).then(r => {
      if (!r.ok) throw new Error(`HTTP ${r.status}`);
      return r.json() as Promise<User>;
    }),
    (e) => `Fetch error: ${e}`
  );
}

const result = await fetchUser(1)
  .map(user => ({ ...user, name: user.name.toUpperCase() }))
  .mapErr(e => ({ code: 'FETCH_FAILED', detail: e }))
  .tap(user => console.log('Fetched:', user.name));

result.match({
  ok: user => console.log('User:', user.name),  // 'ALICE'
  err: e => console.error('Failed:', e.detail),
});
```
