{"id":50729523,"url":"https://github.com/mechanicallabs/ripthrow","last_synced_at":"2026-06-10T07:03:47.290Z","repository":{"id":356384004,"uuid":"1232264656","full_name":"MechanicalLabs/ripthrow","owner":"MechanicalLabs","description":"Rest In Peace, Throw. An opinionated TypeScript library for error handling for pragmatic devs.","archived":false,"fork":false,"pushed_at":"2026-05-21T17:35:04.000Z","size":196,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T02:36:36.907Z","etag":null,"topics":["bun","bunjs","error-handling","rust-like","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/ripthrow","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MechanicalLabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-07T18:55:00.000Z","updated_at":"2026-05-21T17:34:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/MechanicalLabs/ripthrow","commit_stats":null,"previous_names":["mechanicallabs/ripthrow"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/MechanicalLabs/ripthrow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MechanicalLabs%2Fripthrow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MechanicalLabs%2Fripthrow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MechanicalLabs%2Fripthrow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MechanicalLabs%2Fripthrow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MechanicalLabs","download_url":"https://codeload.github.com/MechanicalLabs/ripthrow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MechanicalLabs%2Fripthrow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34140776,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","bunjs","error-handling","rust-like","typescript"],"created_at":"2026-06-10T07:03:46.538Z","updated_at":"2026-06-10T07:03:47.282Z","avatar_url":"https://github.com/MechanicalLabs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ripthrow\n\n[![npm version](https://img.shields.io/npm/v/ripthrow.svg?style=flat-square)](https://www.npmjs.com/package/ripthrow)\n[![CI status](https://img.shields.io/github/actions/workflow/status/MechanicalLabs/ripthrow/ci.yml?branch=main\u0026style=flat-square)](https://github.com/MechanicalLabs/ripthrow/actions/workflows/ci.yml)\n![Bundlephobia Minzipped Size](https://badgen.net/bundlephobia/minzip/ripthrow)\n![https://badgen.net/bundlephobia/dependency-count/ripthrow](https://badgen.net/bundlephobia/dependency-count/ripthrow)\n![https://badgen.net/bundlephobia/tree-shaking/ripthrow](https://badgen.net/bundlephobia/tree-shaking/ripthrow)\n[![License](https://img.shields.io/github/license/MechanicalLabs/ripthrow?style=flat-square)](https://github.com/MechanicalLabs/ripthrow/blob/main/LICENSE)\n\n**Zero-dependency, type-safe error handling for TypeScript.**\n\n`ripthrow` is a lightweight library inspired by Rust's `Result` type and the proposed ECMAScript `?=` operator. It allows you to handle success and failure in a structured way, avoiding `try/catch` blocks and making error states explicit in your types.\n\n![Example code using ripthrow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vtrci8dk4c5mp3mvmsep.png)\n\n## Installation\n\n```bash\nbun add ripthrow\n# or\nnpm install ripthrow\n```\n\n## Quick Start\n\n### Explicit errors with `Ok` and `Err`\n\nFunctions return `Result`, making failure paths visible in the type signature:\n\n```typescript\nimport { Ok, Err, match, type Result } from \"ripthrow\";\n\nfunction getUser(id: string): Result\u003c{ id: string; name: string }, string\u003e {\n  if (!id) {\n     return Err(\"ID is required\");\n  }\n\n  return Ok({ id, name: \"Alice\" });\n}\n\nconst result = getUser(\"123\");\n\nmatch(result, {\n  ok: (user) =\u003e console.log(user.name),\n  err: (msg) =\u003e console.error(`getUser function failed: ${msg}`),\n});\n```\n\n### Wrap throwing code with `safe`\n\n`safe` catches exceptions and returns a `Result` — no `try/catch`:\n\n```typescript\nimport { safe, build } from \"ripthrow\";\n\nconst raw = '{\"valid\": true}';\n\nconst isValid = build(safe(() =\u003e JSON.parse(raw)))\n  .map((data: any) =\u003e data.valid)\n  .unwrapOr(false);\n\nconsole.log(isValid); // true\n```\n\n## Why ripthrow?\n\nHandling errors in TypeScript with native exceptions is inherently unpredictable. Because JavaScript allows you to `throw` anything—from a `string` to a `new Date()`—TypeScript is forced to treat all caught errors as `unknown`. This forces a type-erasure effect where failure states become invisible to the compiler and uncontracted in your function signatures.\n\nHandling errors with exceptions can lead to \"hidden\" control flows. `ripthrow` forces you to acknowledge potential failures, leading to more resilient applications.\n\nWhile there are other libraries, `ripthrow` is designed to be a lightweight \"missing operator\" for modern TypeScript, focusing on minimal overhead and native safety.\n\n\u003cimg width=\"858\" height=\"208\" alt=\"matchErr feature showcase\" src=\"https://github.com/user-attachments/assets/8971da15-e0d8-4f50-ae4d-1e8909a75c09\" /\u003e\n\n\u003e The image presents an usage of `matchErr` utility. It's failing because there's a missing handler for `AuthError`.\n\n### Comparison: ripthrow vs neverthrow\n\n| Feature | ripthrow | neverthrow |\n|---------|----------|------------|\n| **Overhead** | POJO / Object literals | Class-based allocation |\n| **Namespaces** | None (ESM-only) | Uses Namespaces |\n| **Size (min+gzip)** | **~1.6 KB** | ~2.0 KB |\n| **Error Unions** | **Fluent `matchErr().exhaustive()`** | Manual pattern matching |\n\n### Features\n\n- **Minimal Overhead:** `ripthrow` uses simple JavaScript objects (`{ ok: true, value }`) instead of class instances. This ensures faster allocation and zero overhead when chaining operations, while remaining 100% type-safe.\n\n- **Dedicated Exhaustive Matching:** While most libraries require writing manual `switch` statements with `never` checks to handle error unions, `ripthrow` provides a built-in fluent API. `matchErr().exhaustive()` ensures at compile-time that every defined error variant is handled.\n\n- **Collision-Free Errors:** Unique Symbols are used to identify error types, ensuring that error matching is precise and safe from name collisions across different packages or versions.\n\n- **Modern ESM Design:** Built without legacy patterns like namespaces or internal classes, ensuring the best possible compatibility with modern bundlers and tree-shaking.\n\n## Benchmarks\n\n## Benchmark Environment\n\n- Runtime: Bun 1.3.\n\n- CPU: Intel® Core™ i7-7700 × 8\n\n- RAM: 16gb ddr4.\n\n- OS: Fedora Linux 44 (Forty Four)\n\n- Latest Run: `ripthrow@3.0.5`\n\nAll benchmarks run on Bun 1.3 via [tinybench](https://github.com/tinylibs/tinybench) (`bun run bench`).\nHigher ops/s = faster. Latency is per-operation (lower is better).\n\n### Construction\n\n| Pattern | ops/s | Latency | vs native |\n|---------|------:|--------:|----------:|\n| `Ok()` | 26,013,752 | 40.1 ns | — |\n| `Err()` | 25,357,831 | 41.6 ns | — |\n| `throw` | 1,182,517 | 1047.0 ns | **22× slower** |\n| `{ ok: true }` manual | 24,998,347 | 41.7 ns | identical |\n\n\u003e `Ok`/`Err` are object literals — zero overhead vs writing the union manually.\n\u003e `throw` is the expensive one (Error object creation), not ripthrow.\n\n### Wrapping (`safe` vs `try/catch`)\n\n| Pattern | ops/s | Latency |\n|---------|------:|--------:|\n| `safe(success)` | 21,958,738 | 50.6 ns |\n| `try/catch` (no throw) | 26,350,123 | 38.9 ns |\n| `safe(throws)` | 872,088 | 1373.5 ns |\n| `try/catch` (throw) | 1,194,288 | 1073.8 ns |\n| `safeAsync(success)` | 3,285,471 | 322.8 ns |\n| `try/catch async` (success) | 3,276,500 | 323.7 ns |\n\n\u003e `safe` adds \u003c15 ns vs raw try/catch on the success path.\n\u003e On throws, both are bottlenecked by Error object creation — ripthrow is not the overhead.\n\u003e Async paths are identical (bottleneck is Promise scheduling).\n\n### Mapping \u0026 Chaining\n\n| Pattern | ops/s | Latency |\n|---------|------:|--------:|\n| `map` x5 | 14,677,208 | 78.9 ns |\n| `if/else` x5 (native) | 19,481,783 | 58.4 ns |\n| `andThen chain` | 21,421,520 | 50.1 ns |\n| `orElse fallback` | 23,304,137 | 46.9 ns |\n| builder chain (5 ops) | 1,711,691 | 677.4 ns |\n\n\u003e Functional overhead is ~3-5 ns per function call. The builder (fluent API) adds\n\u003e roughly 1-2 ns per method call — effectively zero.\n\n### Matching vs `try/catch`\n\n| Pattern | ops/s | Latency |\n|---------|------:|--------:|\n| `match(Ok)` | 24,680,590 | 43.6 ns |\n| `match(Err)` | 24,835,832 | 42.5 ns |\n| `try/catch` (no throw) | 26,350,123 | 38.9 ns |\n| `try/catch` (throw) | 1,194,288 | 1073.8 ns |\n\n\u003e `match` is within 15% of raw try/catch on the success path.\n\u003e On error paths, `match` is **20× faster** than try/catch with a thrown error.\n\n### Collections\n\n| Pattern | ops/s | Latency |\n|---------|------:|--------:|\n| `all(5 ok)` | 10,445,477 | 110.5 ns |\n| `all(5, last err)` | 14,598,523 | 78.8 ns |\n| `any(5 ok)` | 15,921,334 | 72.8 ns |\n\n### Pattern Matching (`matchErr`)\n\n| Pattern | ops/s | Latency |\n|---------|------:|--------:|\n| `matchErr` (hit — creates Error) | 1,188,146 | 1031.3 ns |\n| `matchErr` (miss — instanceof only) | 10,155,206 | 122.7 ns |\n\n\u003e The \"hit\" path creates the matched `TypedError`, which is the same cost as `new Error()`.\n\u003e The \"miss\" path is just an `instanceof` check — 10M ops/s.\n\n### Context\n\n| Pattern | ops/s | Latency |\n|---------|------:|--------:|\n| `note()` (plain Err) | 1,524,382 | 799.9 ns |\n| `note()` (existing Report) | 733,049 | 1629.7 ns |\n\n\u003e Creating structured `Report` objects has the same cost as `new Error` (~1 µs).\n\n### Real-World Patterns\n\n| Pattern | ops/s | Latency |\n|---------|------:|--------:|\n| parse JSON (ripthrow) | 2,562,169 | 442.3 ns |\n| parse JSON (try/catch) | 8,885,156 | 117.9 ns |\n| deep access (ripthrow) | 3,244,627 | 359.9 ns |\n| deep access (try/catch) | 26,484,065 | 38.9 ns |\n| legacy throw fn (ripthrow) | 20,946,403 | 54.1 ns |\n| legacy throw fn (try/catch) | 27,033,874 | 38.5 ns |\n\n\u003e In real-world usage, ripthrow adds 15-20 ns per operation — well within the\n\u003e \"zero overhead\" claim for all practical purposes. The bottleneck is never\n\u003e the Result type, it's whatever you're doing inside `map`/`andThen`.\n\n### Summary\n\n- **`Ok`/`Err` = native object literal speed.** Same representation, same performance.\n- **`map`/`andThen` = 1-5 ns overhead** per function call.\n- **`match` = faster than try/catch** when errors are actually thrown.\n- **`safe()` = same speed as manual try/catch** on success paths.\n- **`matchErr` \"miss\" path = 10M ops/s**, \"hit\" path = Error construction speed.\n- **Cost center is always `new Error()`**, not ripthrow.\n\n## Licence\n\nThis project is licensed under **MIT** License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmechanicallabs%2Fripthrow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmechanicallabs%2Fripthrow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmechanicallabs%2Fripthrow/lists"}