{"_id":"@alexismora/result-type","name":"@alexismora/result-type","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@alexismora/result-type","version":"1.0.0","description":"A Rust-inspired Result type for TypeScript that makes error handling explicit and unavoidable","author":{"name":"Alexis Mora"},"license":"MIT","main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"tsup src/index.ts --format cjs,esm --dts --clean","prepublishOnly":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git+https://github.com/AlexisMora/result-type.git"},"keywords":["result","result-type","error-handling","rust","typescript","functional","either","option","monad"],"bugs":{"url":"https://github.com/AlexisMora/result-type/issues"},"homepage":"https://github.com/AlexisMora/result-type#readme","devDependencies":{"tsup":"^8.0.0","typescript":"^5.0.0"},"peerDependencies":{"typescript":">=4.5.0"},"peerDependenciesMeta":{"typescript":{"optional":true}},"gitHead":"f1c51521ebf7bda36bab0c2b959e26b3053250d3","_id":"@alexismora/result-type@1.0.0","_nodeVersion":"24.10.0","_npmVersion":"11.6.1","dist":{"integrity":"sha512-0lcVbyV0BBZ71zENymeojcSR1J5Hp8f4nKYT90sYf3x1ZgBcB3o/ztEEk/84FnuxhlTtwqTTEL7Wbx60iYJs7g==","shasum":"2be9554d349f4ecd79e40499619bf0ca43f8aebc","tarball":"https://registry.npmjs.org/@alexismora/result-type/-/result-type-1.0.0.tgz","fileCount":7,"unpackedSize":30368,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGdTNu1gItpKXFjgzoY60TtDJetLq/F7rtSFJ757jpHTAiAYPuTgiKTH0XhFrA67YtNwSZSZWhJCbgIsVt19hxpESw=="}]},"_npmUser":{"name":"alexismora","email":"alexis.mora.sanchez@gmail.com"},"directories":{},"maintainers":[{"name":"alexismora","email":"alexis.mora.sanchez@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/result-type_1.0.0_1765655505397_0.18175613736207152"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-13T19:51:45.307Z","1.0.0":"2025-12-13T19:51:45.548Z","modified":"2025-12-13T19:51:45.791Z"},"maintainers":[{"name":"alexismora","email":"alexis.mora.sanchez@gmail.com"}],"description":"A Rust-inspired Result type for TypeScript that makes error handling explicit and unavoidable","homepage":"https://github.com/AlexisMora/result-type#readme","keywords":["result","result-type","error-handling","rust","typescript","functional","either","option","monad"],"repository":{"type":"git","url":"git+https://github.com/AlexisMora/result-type.git"},"author":{"name":"Alexis Mora"},"bugs":{"url":"https://github.com/AlexisMora/result-type/issues"},"license":"MIT","readme":"# @alexismora/result-type\n\nA Rust-inspired Result type for TypeScript that makes error handling explicit and unavoidable.\n\n## Installation\n\n```bash\nnpm install @alexismora/result-type\n```\n\n## Quick Start\n\n```typescript\nimport { Result, ok, err } from '@alexismora/result-type'\n\nfunction divide(a: number, b: number): Result<number, string> {\n  if (b === 0) {\n    return err(\"Division by zero\")\n  }\n  return ok(a / b)\n}\n\n// Force explicit error handling\nconst result = divide(10, 2)\nconst value = result.expect(\"Division should succeed\") // 5\n\n// Safe handling with defaults\nconst safe = divide(10, 0).unwrapOr(0) // 0\n```\n\n## Why implement Result?\n\nTraditional Typescript error handling with try/catch is easy to ignore. The Result type forces you to handle errors explicitly, making your code more reliable and predictable.\n\n## Key Features\n\n- **Rust-inspired API** - Familiar to Rust developers\n- **Type-safe** - Full TypeScript support with strict inference\n- **Zero dependencies** - Lightweight and fast\n- **Explicit errors** - No more forgotten error handling\n- **Functional** - Chain operations with `map`, `andThen`, etc.\n- **Dual packages** - ESM and CommonJS support\n\n# Usage\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Basic Types](#basic-types)\n- [Creating Results](#creating-results)\n- [Core Methods](#core-methods)\n- [Functional Methods](#functional-methods)\n- [Helper Functions](#helper-functions)\n- [Examples](#examples)\n\n## Overview\n\nThe Result type represents either success (`Ok`) or failure (`Err`). It forces you to handle errors explicitly, preventing the common JavaScript pattern of ignoring errors.\n\n```typescript\nimport { Result, ok, err } from '@alexismora/result-type'\n\ntype MyResult = Result<number, string>\nconst success: MyResult = ok(42)\nconst failure: MyResult = err(\"something went wrong\")\n```\n\n## Basic Types\n\n### `Result<T, E>`\n\nA type that is either `Ok<T>` (success with value of type T) or `Err<E>` (failure with error of type E).\n\n### `Ok<T, E>`\n\nRepresents a successful result containing a value of type `T`.\n\n### `Err<T, E>`\n\nRepresents a failed result containing an error of type `E`.\n\n## Creating Results\n\n### `ok<T, E>(value: T): Result<T, E>`\n\nCreates a successful Result containing the given value.\n\n```typescript\nconst result = ok(42)\n// Result<number, never>\n```\n\n### `err<T, E>(error: E): Result<T, E>`\n\nCreates a failed Result containing the given error.\n\n```typescript\nconst result = err(\"File not found\")\n// Result<never, string>\n```\n\n### Constructor Usage\n\nYou can also use the class constructors directly:\n\n```typescript\nimport { Ok, Err } from '@alexismora/result-type'\n\nconst success = new Ok(42)\nconst failure = new Err(\"error message\")\n```\n\n## Core Methods\n\n### `isOk(): boolean`\n\nReturns `true` if the result is `Ok`. Acts as a type guard in TypeScript.\n\n```typescript\nconst result = ok(42)\n\nif (result.isOk()) {\n  // TypeScript knows this is Ok<number>\n  console.log(result.value) // 42\n}\n```\n\n### `isErr(): boolean`\n\nReturns `true` if the result is `Err`. Acts as a type guard in TypeScript.\n\n```typescript\nconst result = err(\"failed\")\n\nif (result.isErr()) {\n  // TypeScript knows this is Err<string>\n  console.log(result.error) // \"failed\"\n}\n```\n\n### `expect(message: string): T`\n\nReturns the contained `Ok` value. If the result is `Err`, throws an error with your custom message.\n\n**Use this when you have a good reason to expect success and want to fail fast with a clear message.**\n\n```typescript\nconst config = loadConfig().expect(\"Config file must exist\")\n// If loadConfig() returns Err, throws: \"Config file must exist: [error details]\"\n```\n\n### `unwrap(): T`\n\nReturns the contained `Ok` value. If the result is `Err`, throws with a default message.\n\n**Use sparingly - prefer `expect()` for better error messages or safe methods like `unwrapOr()`.**\n\n```typescript\nconst value = ok(42).unwrap() // 42\nconst value = err(\"failed\").unwrap() // Throws: \"Called unwrap on an Err value: failed\"\n```\n\n### `unwrapOr(defaultValue: T): T`\n\nReturns the contained `Ok` value, or the provided default if `Err`.\n\n**Use this when you have a sensible fallback value.**\n\n```typescript\nconst port = getPort().unwrapOr(3000)\n// If getPort() fails, uses 3000 as default\n```\n\n### `unwrapOrElse(fn: (error: E) => T): T`\n\nReturns the contained `Ok` value, or computes a value from the error using the provided function.\n\n**Use this when you need to compute a fallback based on the error.**\n\n```typescript\nconst value = result.unwrapOrElse((error) => {\n  console.error(\"Operation failed:\", error)\n  return getDefaultValue()\n})\n```\n\n## Functional Methods\n\n### `map<U>(fn: (value: T) => U): Result<U, E>`\n\nTransforms the `Ok` value by applying a function. If `Err`, returns the error unchanged.\n\n**Use for transforming successful values while preserving errors.**\n\n```typescript\nconst result = ok(5)\n  .map(x => x * 2)\n  .map(x => x.toString())\n// Result<string, never> = Ok(\"10\")\n\nconst failed = err(\"oops\").map(x => x * 2)\n// Result<number, string> = Err(\"oops\")\n```\n\n### `mapErr<F>(fn: (error: E) => F): Result<T, F>`\n\nTransforms the `Err` value by applying a function. If `Ok`, returns the value unchanged.\n\n**Use for transforming or enriching error information.**\n\n```typescript\nconst result = err(404)\n  .mapErr(code => `HTTP Error ${code}`)\n// Result<never, string> = Err(\"HTTP Error 404\")\n\nconst success = ok(42).mapErr(e => `Error: ${e}`)\n// Result<number, string> = Ok(42)\n```\n\n### `andThen<U>(fn: (value: T) => Result<U, E>): Result<U, E>`\n\nChains operations that return Results. Also known as `flatMap`.\n\n**Use for sequential operations that can each fail.**\n\n```typescript\nconst result = readFile(\"config.json\")\n  .andThen(content => parseJSON(content))\n  .andThen(config => validateConfig(config))\n\n// If any step fails, the error propagates\n// If all succeed, you get the final value\n```\n\n### `or(other: Result<T, E>): Result<T, E>`\n\nReturns this result if `Ok`, otherwise returns the alternative.\n\n**Use for providing fallback operations.**\n\n```typescript\nconst result = readFromCache()\n  .or(readFromDatabase())\n  .or(readFromAPI())\n// Uses the first successful result\n```\n\n### `match<U>(patterns: { ok: (value: T) => U, err: (error: E) => U }): U`\n\nPattern matching for Results. Calls one function or the other based on the variant.\n\n**Use for handling both cases explicitly and transforming to a common type.**\n\n```typescript\nconst message = result.match({\n  ok: (value) => `Success: ${value}`,\n  err: (error) => `Failed: ${error}`\n})\n\nconst status = apiCall().match({\n  ok: (data) => ({ success: true, data }),\n  err: (error) => ({ success: false, error })\n})\n```\n\n## Helper Functions\n\n### `tryCatch<T, E>(fn: () => T, errorHandler?: (error: unknown) => E): Result<T, E>`\n\nWraps a function that might throw an exception into a Result.\n\n**Use to convert exception-based code to Result-based code.**\n\n```typescript\nconst result = tryCatch(\n  () => JSON.parse(jsonString),\n  (error) => `Parse error: ${error}`\n)\n\nif (result.isOk()) {\n  console.log(\"Parsed:\", result.value)\n} else {\n  console.error(\"Failed:\", result.error)\n}\n```\n\nWithout error handler, the caught error is used directly:\n\n```typescript\nconst result = tryCatch(() => riskyOperation())\n// Result<ReturnType, unknown>\n```\n\n### `tryCatchAsync<T, E>(fn: () => Promise<T>, errorHandler?: (error: unknown) => E): Promise<Result<T, E>>`\n\nAsync version of `tryCatch`. Wraps an async function that might throw.\n\n**Use to convert promise rejections into Results.**\n\n```typescript\nconst result = await tryCatchAsync(\n  async () => await fetch(url).then(r => r.json()),\n  (error) => `Network error: ${error}`\n)\n\nresult.match({\n  ok: (data) => console.log(\"Data:\", data),\n  err: (error) => console.error(\"Error:\", error)\n})\n```\n\n## Examples\n\n### Basic Error Handling\n\n```typescript\nfunction divide(a: number, b: number): Result<number, string> {\n  if (b === 0) {\n    return err(\"Division by zero\")\n  }\n  return ok(a / b)\n}\n\nconst result = divide(10, 2)\nconst value = result.expect(\"Division should succeed\") // 5\n\nconst bad = divide(10, 0)\nconst safe = bad.unwrapOr(0) // 0\n```\n\n### File Operations\n\n```typescript\nfunction readConfig(): Result<Config, string> {\n  return tryCatch(\n    () => {\n      const content = fs.readFileSync(\"config.json\", \"utf8\")\n      return JSON.parse(content)\n    },\n    (error) => `Failed to read config: ${error}`\n  )\n}\n\nconst config = readConfig()\n  .map(c => ({ ...c, loaded: true }))\n  .unwrapOr(getDefaultConfig())\n```\n\n### API Calls\n\n```typescript\nasync function fetchUser(id: string): Promise<Result<User, ApiError>> {\n  return tryCatchAsync(\n    async () => {\n      const response = await fetch(`/api/users/${id}`)\n      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}`)\n      }\n      return response.json()\n    },\n    (error) => ({\n      code: \"FETCH_ERROR\",\n      message: String(error)\n    })\n  )\n}\n\n// Usage\nconst result = await fetchUser(\"123\")\n\nconst user = result.match({\n  ok: (user) => user,\n  err: (error) => {\n    console.error(\"Failed to fetch user:\", error)\n    return null\n  }\n})\n```\n\n### Chaining Operations\n\n```typescript\nfunction processUserData(userId: string): Result<ProcessedData, string> {\n  return fetchUserFromDB(userId)\n    .andThen(user => validateUser(user))\n    .andThen(user => enrichUserData(user))\n    .andThen(data => processData(data))\n    .mapErr(error => `User processing failed: ${error}`)\n}\n\n// If any step fails, the chain short-circuits and returns the error\n// If all succeed, you get the final ProcessedData\n```\n\n### Type-Safe Error Handling\n\n```typescript\ntype AppError =\n  | { type: \"NotFound\"; resource: string }\n  | { type: \"Unauthorized\"; reason: string }\n  | { type: \"Validation\"; errors: string[] }\n\nfunction getResource(id: string): Result<Resource, AppError> {\n  if (!isAuthenticated()) {\n    return err({ type: \"Unauthorized\", reason: \"Not logged in\" })\n  }\n\n  const resource = db.find(id)\n  if (!resource) {\n    return err({ type: \"NotFound\", resource: id })\n  }\n\n  return ok(resource)\n}\n\nconst result = getResource(\"123\")\n\nresult.match({\n  ok: (resource) => displayResource(resource),\n  err: (error) => {\n    switch (error.type) {\n      case \"NotFound\":\n        show404(error.resource)\n        break\n      case \"Unauthorized\":\n        redirectToLogin(error.reason)\n        break\n      case \"Validation\":\n        showErrors(error.errors)\n        break\n    }\n  }\n})\n```\n\n### Combining Multiple Results\n\n```typescript\nfunction loadAppData(): Result<AppData, string> {\n  const config = loadConfig()\n  const user = loadUser()\n  const settings = loadSettings()\n\n  if (config.isErr()) return config\n  if (user.isErr()) return user\n  if (settings.isErr()) return settings\n\n  return ok({\n    config: config.value,\n    user: user.value,\n    settings: settings.value\n  })\n}\n```\n\n### Graceful Degradation\n\n```typescript\nconst data = fetchFromCache()\n  .or(fetchFromDatabase())\n  .or(fetchFromAPI())\n  .unwrapOr(getDefaultData())\n\n// Tries cache first, then database, then API\n// Falls back to default data if all fail\n```\n\n## Best Practices\n\n1. **Use `expect()` with descriptive messages** when you have a good reason to believe the operation should succeed.\n\n2. **Prefer `unwrapOr()` over `unwrap()`** when you have a sensible default value.\n\n3. **Use `andThen()` for chaining** operations that can each fail - it's cleaner than nested if/else.\n\n4. **Use `match()` for exhaustive handling** when you need to handle both cases explicitly.\n\n5. **Use typed errors** (discriminated unions) for better error handling and IDE support.\n\n6. **Wrap external APIs** with `tryCatch` or `tryCatchAsync` to convert exceptions to Results.\n\n7. **Don't mix paradigms** - once you start using Result, avoid mixing it with try/catch in the same code path.\n\n## License\n\nMIT\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## Repository\n\nhttps://github.com/AlexisMora/result-type","readmeFilename":"README.md","_rev":"1-2404ac5077cec7370e8d21f70394995f"}