# @hulla/control

> Return typed success or failure values so callers can handle expected errors before transforming the result.

## Useful when

- You want callers to handle expected failures without relying on exceptions.
- Success and error values should stay distinct even when their payload types overlap.
- You need to compose transformations across synchronous or asynchronous values.

`@hulla/control` lets a function return success or failure as a value. Return `Ok` with the data or `Err` with the problem, then let the caller check which one it received.

```ts
import { err, ok, type Result } from '@hulla/control'

function findTitle(id: string): Result<string, Error> {
  return id === 'welcome' ? ok('Welcome') : err(new Error('Title not found'))
}
```

This is useful when a failure is part of the function's contract, such as a missing record or invalid input. If callers already expect an exception boundary, keep throwing and use [`tcf()` to convert that boundary](https://hulla.dev/docs/control/attempts.md). For ordinary internal work with no meaningful failure case, a plain return value is simpler.

Build the [config checker](https://hulla.dev/guides/control/config-checker.md) to combine parsing, validation, and error reporting in one small command.

**Interactive example:&#x20;**&#x42;reak the JSON or supply an invalid replica count. Both become typed failures; later work stays unreached.

The browser runs @hulla/control to convert a JSON exception and invalid deployment config into explicit failure results. Nothing is deployed.

```ts
import { tcf, err, ok } from '@hulla/control'

const parsed = tcf({
  try: () => JSON.parse(source) as unknown,
  catch: () => new Error('Invalid JSON'),
})
if (parsed.isErr()) return parsed
// Validate the shape before building the deployment plan.
// Return err(problem) for domain failures, ok(plan) on success.
```

[Build the working example](https://hulla.dev/guides/control/quick-start.md)

## Choose how to consume the result

| You want to…                                | Use                                                                                                             |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| Run different code for success and failure  | [`isOk()` or `isErr()`](https://hulla.dev/docs/control/results.md#narrow-when-the-branches-need-different-work) |
| Produce one value from either branch        | [`match()`](https://hulla.dev/docs/control/results.md#match-when-both-branches-produce-one-value)               |
| Transform a payload and preserve its branch | [`map()` or `mapErr()`](https://hulla.dev/docs/control/chaining.md)                                             |

| Need                                                           | Start here                                                     |
| -------------------------------------------------------------- | -------------------------------------------------------------- |
| Install the package and build a first result                   | [Quick start](https://hulla.dev/guides/control/quick-start.md) |
| Construct, narrow, and inspect success or error values         | [Results](https://hulla.dev/docs/control/results.md)           |
| Transform values while keeping the result branch               | [Chaining](https://hulla.dev/docs/control/chaining.md)         |
| Catch exceptions and rejected promises at an explicit boundary | [Attempts](https://hulla.dev/docs/control/attempts.md)         |

The result branch carries its own tag (`'ok'` or `'error'` by default), so `Result<string, string>` remains unambiguous. Continue with the [quick start](https://hulla.dev/guides/control/quick-start.md) to install `@hulla/control` and call a function that returns both outcomes.
