npm package: @mkvlrn/result
Description: Simple Result type/pattern for TypeScript
Author: Mike Valeriano
Latest version: 5.0.8

# @mkvlrn/result

Dead simple Result pattern for TypeScript.

No `.map()`, no `.flatMap()`, no `.andThen()`, no `.orElse()`, no `.unwrap()`, no monadic gymnastics. Just a type, two functions, and TypeScript doing what TypeScript already does well.

[![npm](https://img.shields.io/npm/v/@mkvlrn/result)](https://www.npmjs.com/package/@mkvlrn/result)

## Why this one?

There are dozens of Result libraries for TypeScript. Nearly all of them bolt on method chaining, transformation pipelines, and functional programming utilities that turn a simple concept into an entire paradigm.

This package does **one thing**: gives you a type-safe `Result<T, E>` discriminated union with `ok()` and `err()` constructors. You use `if/else` to handle it. TypeScript narrows the type for you. That's the whole API.

**The entire implementation is ~35 lines. Zero runtime dependencies. Four exports.**

If you need `.map().flatMap().andThen().orElse().unwrapOr()` chains, use [neverthrow](https://github.com/supermacro/neverthrow) or [ts-results](https://github.com/vultix/ts-results). They're good libraries. This isn't that.

## Installation

```bash
pnpm add @mkvlrn/result
```

## API

| Export              | What it does                                 |
| ------------------- | -------------------------------------------- |
| `Result<T, E>`      | Union type representing success or failure   |
| `AsyncResult<T, E>` | `Promise<Result<T, E>>` for async operations |
| `ok(value)`         | Creates a success result                     |
| `err(error)`        | Creates an error result                      |

That's it. That's the whole thing.

## Usage

```typescript
import { type Result, type AsyncResult, ok, err } from "@mkvlrn/result";
```

### Create results, check results

```typescript
function divide(a: number, b: number): Result<number, Error> {
  if (b === 0) {
    return err(new Error("Division by zero"));
  }
  return ok(a / b);
}

const result = divide(10, 2);
if (result.isOk) {
  console.log(result.value); // number - TypeScript knows
}

if (result.isError) {
  console.log(result.error.message); // Error - TypeScript knows
}
```

No `.unwrap()`. No `.expect()`. Just an `if` statement and the compiler handles the rest.

### Async Operations

```typescript
async function fetchUser(id: number): AsyncResult<User, Error> {
  try {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) {
      return err(new Error(`HTTP ${response.status}`));
    }
    const user = await response.json();
    return ok(user);
  } catch (error) {
    return err(error instanceof Error ? error : new Error("Unknown error"));
  }
}
```

`AsyncResult<T, E>` is just `Promise<Result<T, E>>`. It's a type alias, not a class, not a wrapper, not a monad.

### Custom Error Types

```typescript
class ValidationError extends Error {
  readonly code: number;

  constructor(code: number, message: string) {
    super(message);
    this.name = "ValidationError";
    this.code = code;
  }
}

function validateEmail(email: string): Result<string, ValidationError> {
  if (!email.includes("@")) {
    return err(new ValidationError(400, "bad-email"));
  }
  return ok(email);
}

const result = validateEmail("invalid-email");
if (result.isError) {
  // TypeScript knows this is a ValidationError, not just Error
  console.log(`${result.error.code}: ${result.error.message}`); // 400: bad-email
}
```

## License

MIT