npm package: @rsnk/result
Description: A TypeScript port of Rust's Result<T, E> type, providing a type-safe way to handle errors and avoid exceptions.
Author: Vladyslav Rasenko
Latest version: 1.0.0

# Result

[![NPM Version](https://img.shields.io/npm/v/@rsnk/result)](https://www.npmjs.com/package/@rsnk/result)
[![NPM License](https://img.shields.io/npm/l/@rsnk/result)](https://www.npmjs.com/package/@rsnk/result)
[![NPM Downloads](https://img.shields.io/npm/dy/@rsnk/result)](https://www.npmjs.com/package/@rsnk/result)
[![Bundle Size](https://img.shields.io/bundlephobia/minzip/@rsnk/result)](https://bundlephobia.com/result?p=@rsnk/result)

A TypeScript port of Rust's `Result<T, E>` type, providing a type-safe way to handle errors and avoid exceptions.

## Table of Contents
- [Installation](#installation)
- [Overview](#overview)
- [Quick Start](#quick-start)
- [Common Patterns](#common-patterns)
- [TypeScript Type Narrowing](#typescript-type-narrowing)
- [Comparison with Other Approaches](#comparison-with-other-approaches)
- [Design Philosophy](#design-philosophy)
- [Contributing](#contributing)
- [License](#license)
- [API Reference](#api-reference)

## Installation

Install the package using your favorite package manager:

```bash
npm install @rsnk/result
```

or

```bash
yarn add @rsnk/result
```

## Overview

The `Result` type represents either success (`Ok`) or failure (`Err`). This pattern eliminates the ambiguity of throwing exceptions and makes error handling explicit and type-safe.

```typescript
// Instead of this:
try {
  const user = getUser(id);
  console.log(user.name);
} catch (e) {
  console.error("Failed:", e);
}

// Write this:
const result = getUser(id); // Result<User, Error>
result.match({
  Ok: user => console.log(user.name),
  Err: err => console.error("Failed:", err)
});
```

## Quick Start
```typescript
import R from "@rsnk/result";
```

### Creating Results

```typescript
// Create a success (Ok)
const success = R.ok(42);            // Result<number, never>

// Create a failure (Err)
const failure = R.err("not found");  // Result<never, string>

// Wrap a function that might throw
const res = R.tryCatch(() => JSON.parse(str)); // Result<any, unknown>

// Wrap a Promise
const asyncRes = await R.fromPromise(fetch("/api/data")); // Result<Response, unknown>
```

### Basic Operations

```typescript
// Check status
if (result.isOk()) {
  console.log(result.unwrap());
}

// Transform values
result
  .map(x => x * 2)
  .mapErr(err => `Error: ${err}`)
  .unwrapOr(0);

// Pattern matching
result.match({
  Ok: value => console.log("Success:", value),
  Err: error => console.error("Error:", error)
});
```

## Common Patterns

### Chaining Operations (Railway Oriented Programming)

Propagate errors automatically while applying transformations to successful values.

```typescript
function getProcessedData(input: string): Result<number, string> {
  return parseInput(input)           // Result<Input, string>
    .andThen(validateInput)          // Result<Input, string>
    .map(processData)                // Result<Data, string>
    .map(data => data.value);        // Result<number, string>
}
```

### Async Error Handling

Handle async operations without try-catch hell.

```typescript
const result = await R.fromPromise(fetchUser(id))
  .andThenAsync(async user => await fetchPreferences(user.id))
  .map(prefs => prefs.theme);
```

### Safe Unwrapping

Avoid throwing exceptions when accessing values.

```typescript
// Safe defaults
const port = getConfig("port")
  .map(Number)
  .unwrapOr(8080);

// Computed defaults
const config = loadConfig()
  .unwrapOrElse(err => defaultConfig);
```

## TypeScript Type Narrowing

The Result type integrates seamlessly with TypeScript's type system:

```typescript
const res: Result<number, string> = someOperation();

// Type guards work automatically
if (res.isOk()) {
  const val: number = res.unwrap(); // Safe!
} else {
  const err: string = res.unwrapErr(); // Safe!
}

// Type predicates
if (res.isOkAnd(x => x > 10)) {
  // TypeScript knows it's Ok and potentially narrows type based on predicate
}
```

## Comparison with Other Approaches

### vs Exceptions

**Exceptions:**
- Implicit control flow (GOTO).
- Easy to forget to handle.
- Function signatures don't reveal possible errors.

**Result:**
- Explicit control flow.
- Forced error handling (cannot access value without handling error).
- Function signatures document success and failure types (`Result<User, DatabaseError>`).

### vs Returning null/false

**Returning null/false:**
- No error context (why did it fail?).
- Ambiguous (is `null` a valid value or an error?).

**Result:**
- `Err` contains rich error information.
- Clear distinction between success value and error value.

## Design Philosophy

This implementation prioritizes **developer experience and productivity**. Key design decisions:

- **Class-Based**: For better IDE autocomplete and method chaining.
- **Separate Ok/Err Classes**: Optimized for performance and clean implementation.
- **Heavy Async Support**: First-class support for `Promise` integration (`mapAsync`, `andThenAsync`), as modern TS is heavily async.

## Contributing

Contributions are welcome! Please open an issue or submit a pull request.

## License

MIT

## API Reference

### Factory Functions

#### `R.ok<T, E>(value: T): Result<T, E>`
Creates a success `Ok` result.

#### `R.err<E, T>(error: E): Result<T, E>`
Creates a failure `Err` result.

#### `R.tryCatch<T, E>(fn: () => T): Result<T, E>`
Executes a function and returns `Ok(value)` or `Err(error)` if it throws.

#### `R.fromPromise<T, E>(promise: Promise<T>): Promise<Result<T, E>>`
Converts a Promise to a Result. Resolves to `Ok` or rejects to `Err`.


### Type Checking

#### `isOk(): this is Ok<T, E>`
Returns `true` if the result is `Ok`.

#### `isErr(): this is Err<T, E>`
Returns `true` if the result is `Err`.

#### `isOkAnd(predicate: (value: T) => boolean): boolean`
Returns `true` if `Ok` and the predicate matches.

#### `isErrAnd(predicate: (error: E) => boolean): boolean`
Returns `true` if `Err` and the predicate matches.

### Extraction (Unwrapping)

#### `unwrap(): T`
Returns the value. Throws if `Err`.

#### `unwrapErr(): E`
Returns the error. Throws if `Ok`.

#### `expect(msg: string): T`
Returns the value. Throws with message if `Err`.

#### `unwrapOr<U>(default: U): T | U`
Returns the value or a default.

#### `unwrapOrElse<U>(fn: (err: E) => U): T | U`
Returns the value or computes a default from the error.

### Transformations

#### `map<U>(fn: (val: T) => U): Result<U, E>`
Transforms the `Ok` value.

#### `mapErr<F>(fn: (err: E) => F): Result<T, F>`
Transforms the `Err` value.

#### `mapOr<U>(default: U, fn: (val: T) => U): U`
Maps and unwraps, returning a default if `Err`.

#### `mapOrElse<U>(defaultFn: (err: E) => U, fn: (val: T) => U): U`
Maps and unwraps, computing default from error if `Err`.

#### `flatten()`
Flattens `Result<Result<T, E>, E>` to `Result<T, E>`.

### Chaining

#### `andThen<U>(fn: (val: T) => Result<U, E>): Result<U, E>`
Chains operations that may fail (flatMap).

#### `and<U>(res: Result<U, E>): Result<U, E>`
Returns `res` if `Ok`, otherwise returns self (`Err`).

#### `or<F>(res: Result<T, F>): Result<T, F>`
Returns self if `Ok`, otherwise returns `res`.

#### `orElse<F>(fn: (err: E) => Result<T, F>): Result<T, F>`
Returns self if `Ok`, otherwise calls `fn` to recover from error.

### Async

#### `mapAsync<U>(fn: (val: T) => Promise<U>): Promise<Result<U, E>>`
Async version of `map`.

#### `andThenAsync<U>(fn: (val: T) => Promise<Result<U, E>>): Promise<Result<U, E>>`
Async version of `andThen`.

#### `transposePromise()`
Converts `Result<Promise<T>, E>` to `Promise<Result<T, E>>`.

### Side Effects

#### `inspect(fn: (val: T) => void): Result<T, E>`
Runs `fn` if `Ok`.

#### `inspectErr(fn: (err: E) => void): Result<T, E>`
Runs `fn` if `Err`.

### Pattern Matching

#### `match({ Ok: fn, Err: fn }): U`
Pattern matching.