{"id":13566951,"url":"https://github.com/hazae41/result","last_synced_at":"2025-04-22T13:35:41.184Z","repository":{"id":136123549,"uuid":"609567445","full_name":"hazae41/result","owner":"hazae41","description":"Rust-like Result for TypeScript","archived":false,"fork":false,"pushed_at":"2024-11-14T06:30:20.000Z","size":207,"stargazers_count":35,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-19T18:06:56.655Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hazae41.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"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},"funding":{"github":["hazae41"],"patreon":"hazae41"}},"created_at":"2023-03-04T15:14:14.000Z","updated_at":"2024-11-14T06:30:23.000Z","dependencies_parsed_at":"2024-06-19T05:17:34.795Z","dependency_job_id":"272b9f9d-69e6-416d-9e6c-d25a757c40ec","html_url":"https://github.com/hazae41/result","commit_stats":{"total_commits":204,"total_committers":1,"mean_commits":204.0,"dds":0.0,"last_synced_commit":"609856722ca6b1463fdd1eb9045eb623dd8bed40"},"previous_names":[],"tags_count":76,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fresult","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fresult/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fresult/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fresult/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hazae41","download_url":"https://codeload.github.com/hazae41/result/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250249330,"owners_count":21399438,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-08-01T13:02:20.158Z","updated_at":"2025-04-22T13:35:41.166Z","avatar_url":"https://github.com/hazae41.png","language":"TypeScript","funding_links":["https://github.com/sponsors/hazae41","https://patreon.com/hazae41"],"categories":["TypeScript"],"sub_categories":[],"readme":"# Result\n\nRust-like Result for TypeScript\n\n```bash\nnpm i @hazae41/result\n```\n\n[**Node Package 📦**](https://www.npmjs.com/package/@hazae41/result)\n\n## Features\n\n### Current features\n- 100% TypeScript and ESM\n- No external dependencies\n- Similar to Rust\n- `wrap()`/`unwrap()`/`rewrap()` conversion (async/sync)\n- `ok()`/`err()` for converting to Option from `@hazae41/option` (with optional chaining `?.`)\n- `isOk()`/`isErr()` type guards\n- `map()`/`tryMap()` mapping (async/sync)\n- `unwrapOr()` default value\n\n## Why\n\nWhen designing a function, you never know how to return that the action failed\n\n### If you throw an Error\n\nThis is the standard way of dealing with errors\n\nBut you are forced to try-catch, you also need to be aware that the function may throw\n\n```typescript\n// does this throw? I don't know\nfunction doSomething(): string\n\ntry {\n  const result = doSomething()\n  // use result\n} catch(e: unknown) {\n  // use e (you don't know what it is)\n}\n```\n\nAnd the error is not typed, so you often end up checking if that's an error, and if it is not, you don't know what to do\n\n```typescript\ntry { \n  // ...\n} catch(e: unknown) {\n  if (e instanceof Error)\n    // use e\n  else\n    // what should I do now? rethrow?\n}\n```\n\n### If you return an error\n\nThe advantage is that the error is explicit (you know it can fail) and typed\n\nBut you have to check for `instanceof Error` each time\n\n```typescript\nfunction doSomething(): string | Error\n\nconst result = doSomething()\n\nif (result instanceof Error)\n  throw result\n\n// use result\n```\n\n### If you return undefined\n\nThe advantage is that you can use optional chaining `?.`\n\n```typescript\nfunction doSomething(): string | undefined\n\nconst maybeSlice = doSomething()?.slice(0, 5)\n```\n\nBut if you want to throw, you have to explicitly check for `undefined`, and the \"burden of naming the error\" is on you instead of the function you used\n\n```typescript\nfunction doSomething(): string | undefined\n\nconst result = doSomething()\n\nif (result === undefined)\n  throw new Error(`something failed, idk`)\n\n// use result\n```\n\nAnd `undefined` may mean something else, for example, a function that reads from IndexedDB:\n\n```typescript\nfunction read\u003cT\u003e(key: string): T | undefined\n```\n\nDoes `undefined` mean that the read failed? Or does it mean that the key doesn't exist?\n\n### If you return a Result\n\nThis is the way\n\nIt's a simple object that allows you to do all of the methods above, and even more: \n- Throw with `unwrap()`\n- Get the data and error with `ok()` and `err()`, with support for optional chaining `?.` \n- Check the data and error with `isOk()` and `isErr()` type guards\n- Map the data and error with `map()` and `mapErr()`\n- Use a default value with `unwrapOr()`\n\n## Usage\n\n### Unwrapping\n\nUse `unwrap()` to get the inner data if Ok or throw the inner error if Err\n\n```typescript\nimport { Result, Ok, Err } from \"@hazae41/result\"\n\nfunction unwrapAndIncrement(result: Result\u003cnumber\u003e): number {\n  return result.unwrap() + 1\n}\n\nunwrapAndIncrement(Ok.new(0)) // will return 1\nunwrapAndIncrement(Err.error(\"Error\"))) // will throw Error(\"Error\")\n```\n\n### Optional\n\nUse `ok()` and `err()` to get an Option, and use `inner` to get the inner value if `Some`, or `undefined` if `None`\n\n```typescript\nfunction maybeSlice(result: Result\u003cstring\u003e): string | undefined {\n  return result.ok().inner?.slice(0, 5)\n}\n\nmaybeSlice(new Ok(\"hello world\")) // will return \"hello\"\nmaybeSlice(Err.error(\"Error\")) // will return undefined \n```\n\n### Safe mapping\n\nYou can easily map inner data if Ok and do nothing if Err, with support for async and sync\n\n```typescript\nimport { Result, Ok, Err } from \"@hazae41/result\"\n\nfunction tryIncrement(result: Result\u003cnumber, Error\u003e): Result\u003cnumber, Error\u003e {\n  return result.mapSync(x =\u003e x + 1)\n}\n\ntryIncrement(new Ok(0)) // Ok(1)\ntryIncrement(Err.error(\"Error\")) // Err(Error(\"Error\"))\n```\n\n### Type guards\n\nYou can easily check for Ok or Err and it's fully type safe\n\n```typescript\nimport { Result, Ok, Err } from \"@hazae41/result\"\n\nfunction incrementOrFail(result: Result\u003cnumber, Error\u003e): number | Error {\n  if (result.isOk())\n    result // Ok\u003cnumber\u003e\n  else\n    result // Err\u003cError\u003e\n}\n```\n\n### Wrapping\n\nYou can easily wrap try-catch patterns, with support for async and sync\n\n```typescript\nconst result = Result.runAndWrapSync(() =\u003e {\n  if (something)\n    return 12345\n  else\n    throw new Error(\"It failed\")\n})\n```\n\n### Rewrapping\n\nIf another library implements its own Result type, as long as it has `unwrap()`, you can rewrap it to this library in one function\n\n```typescript\ninterface OtherResult\u003cT\u003e {\n  unwrap(): T\n}\n\nfunction rewrapAndIncrement(other: OtherResult\u003cnumber\u003e): Result\u003cnumber\u003e {\n  return Result.rewrap(other).mapSync(x =\u003e x + 1)\n}\n```\n\n### Panicking\n\nWhen using Result, throwing is seen as \"panicking\", if something is thrown and is not expected, it should stop the software\n\nSo the try-catch pattern is prohibited in Result kingdom, unless you use external code from a library that doesn't use Result\n\n```tsx\ntry {\n  return new Ok(doSomethingThatThrows())\n} catch(e: unknown) {\n  return new Err(e as Error)\n}\n```\n\nBut, sometimes, you want to do a bunch of actions, unwrap everything, catch everyting and return Err\n\n```tsx\n/**\n * BAD EXAMPLE\n **/\ntry {\n  const x = tryDoSomething().unwrap()\n  const y = tryDoSomething().unwrap()\n  const z = tryDoSomething().unwrap() \n\n  return new Ok(doSomethingThatThrows(x, y, z))\n} catch(e: unknown) {\n  return new Err(e as Error)\n}\n```\n\nBut what if you only want to catch errors thrown from `Err.unwrap()`, and not errors coming from `doSomethingThatThrows()`?\n\nYou can do so by using `Result.unthrow()`, it will do a try-catch but only catch errors coming from `Err.throw()`\n\n```tsx\nreturn Result.unthrowSync\u003cvoid, Error\u003e(t =\u003e {\n  const x = tryDoSomething().throw(t) \n  const y = tryDoSomething().throw(t)\n  const z = tryDoSomething().throw(t)\n\n  return new Ok(doSomethingThatThrows(x, y, z))\n})\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhazae41%2Fresult","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhazae41%2Fresult","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhazae41%2Fresult/lists"}