> For the complete documentation index, see [llms.txt](https://funkcia.lukemorales.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://funkcia.lukemorales.io/data-types/optionasync/error-propagation.md).

# Error Propagation

Funkcia offers a concise and convenient way to write your code in a more imperative style that utilizes the native scope provided by the generator syntax. This syntax is more linear and resembles normal synchronous code.

Drawing primarily from Rust's `?` operator for error propagation, and inspired by Gleam's [`use` expressions](https://gleam.run/news/v0.25-introducing-use-expressions/), [neverthrow's `safeTry`](https://github.com/supermacro/neverthrow?tab=readme-ov-file#safetry), and [Effect's `gen`](https://effect.website/docs/getting-started/using-generators/#_top) functions, the following functions provide a clean way to handle sequential operations while maintaining proper error handling and type safety.

#### use

Evaluates an *async* generator early returning when an `Option.None` is propagated or returning the `OptionAsync` returned by the generator.

* Each `yield*` automatically awaits and unwraps the `OptionAsync` value or propagates `None`.
* If any operation resolves to `Option.None`, the entire generator exits early.

<pre class="language-typescript" data-overflow="wrap"><code class="lang-typescript">import { OptionAsync } from 'funkcia';

declare const safeReadFile: (path: string) => OptionAsync&#x3C;string>;
declare const safeWriteFile: (path: string, content: string) => OptionAsync&#x3C;string>;

//          ┌─── OptionAsync&#x3C;string>
//          ▼
const mergedContent = OptionAsync.use(async function* () {
  const <a data-footnote-ref href="#user-content-fn-1">fileA</a> = yield* safeReadFile('data.txt');
  const <a data-footnote-ref href="#user-content-fn-2">fileB</a> = yield* safeReadFile('non-existent-file.txt'); // returns OptionAsync.None immediately

  return safeWriteFile('output.txt', `${fileA}\n${fileB}`); // doesn't run
});
// Output: OptionAsync
</code></pre>

#### fn

Returns a function that evaluates an *async* generator when called with the defined arguments, early returning when an `Option.None` is propagated or returning the `OptionAsync` returned by the generator.

* Each `yield*` automatically awaits and unwraps the `OptionAsync` value or propagates `None`.
* If any operation resolves to `Option.None`, the entire generator exits early.

<pre class="language-typescript"><code class="lang-typescript">import { OptionAsync } from 'funkcia';

declare const safeReadFile: (path: string) => OptionAsync&#x3C;string>;
declare const safeWriteFile: (path: string, content: string) => OptionAsync&#x3C;string>;

//          ┌─── (output: string, pathA: string, pathB: string) => OptionAsync&#x3C;string>
//          ▼
const safeMergeFiles = OptionAsync.fn(async function* (output: string, pathA: string, pathB: string) {
  const <a data-footnote-ref href="#user-content-fn-1">fileA</a> = yield* safeReadFile(pathA);
  const <a data-footnote-ref href="#user-content-fn-2">fileB</a> = yield* safeReadFile(pathB);

  return safeWriteFile(output, `${fileA}\n${fileB}`);
});

const mergedContent = safeMergeFiles('output.txt', 'data.txt', 'updated-data.txt');
// Output: OptionAsync
</code></pre>

### Understanding the use method

The `use` method provides a way to write sequential operations that might fail, similar to Rust's `?` operator. It lets you write code that looks synchronous while safely handling potential failures.

It essentially creates a "safe context" where you can work with values as if they were guaranteed to exist, while maintaining all the safety guarantees of `OptionAsync`. If anything fails, the failure propagates automatically. Like an electronic relay that controls current flow, ⁠relay controls computation flow: ⁠`Option.Some` continues, ⁠`Option.None` breaks the circuit.

Here's a practical example:

```typescript
import { OptionAsync } from 'funkcia';

declare function findUser(id: string): OptionAsync<User>;
declare function getUserPermissions(user: User): OptionAsync<Permissions>;
declare function checkAccess(permissions: Permissions, resource: string): OptionAsync<Access>;

const access = OptionAsync.use(async function* () {
  // First, try to find the user
  const user = yield* findUser('user_123');
  // If user is found (`findUser` returns `OptionAsync.Some(User)`, get their permissions
  const permissions = yield* getUserPermissions(user);

  // If all steps succeed, we can use the accumulated context to check access to specific resource
  return checkAccess(permissions, 'api-key');
});
```

The equivalent code without `use` would be much more nested:

```typescript
import { Option } from 'funkcia';

declare function findUser(id: string): Option<User>;
declare function getUserPermissions(user: User): Option<Permissions>;
declare function checkAccess(permissions: Permissions, resource: string): Option<Access>;

const access = findUser('user_123')
  .andThen(user =>
    getUserPermissions(user)
      .andThen(permissions =>
        checkAccess(permissions, 'api-key')
      )
  );
```

Or with intermediate variables:

{% code fullWidth="false" %}

```typescript
import { Option } from 'funkcia';

declare function findUser(id: string): Option<User>;
declare function getUserPermissions(user: User): Option<Permissions>;
declare function checkAccess(permissions: Permissions, resource: string): Option<Access>;

const maybeUser = findUser('user_123');
const maybePermissions = maybeUser.andThen(getUserPermissions);

const access = maybePermissions.andThen(permissions => {
  return checkAccess(permissions, 'api-key');
});
```

{% endcode %}

[^1]: const fileA: string

[^2]: const fileB: string


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://funkcia.lukemorales.io/data-types/optionasync/error-propagation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
