{"id":36823693,"url":"https://github.com/haideralsh/ts-result","last_synced_at":"2026-01-12T14:02:43.436Z","repository":{"id":57114908,"uuid":"324447390","full_name":"haideralsh/ts-result","owner":"haideralsh","description":"A zero-dependency Result type for TypeScript","archived":false,"fork":false,"pushed_at":"2021-09-20T20:52:10.000Z","size":332,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-03T19:22:48.812Z","etag":null,"topics":["error-handling","generics","result-type","typescript"],"latest_commit_sha":null,"homepage":"","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/haideralsh.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}},"created_at":"2020-12-25T23:14:17.000Z","updated_at":"2025-09-29T01:19:08.000Z","dependencies_parsed_at":"2022-08-22T09:10:31.025Z","dependency_job_id":null,"html_url":"https://github.com/haideralsh/ts-result","commit_stats":null,"previous_names":["haideralsh/result-ts"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/haideralsh/ts-result","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haideralsh%2Fts-result","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haideralsh%2Fts-result/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haideralsh%2Fts-result/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haideralsh%2Fts-result/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haideralsh","download_url":"https://codeload.github.com/haideralsh/ts-result/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haideralsh%2Fts-result/sbom","scorecard":{"id":452865,"data":{"date":"2025-08-11","repo":{"name":"github.com/haideralsh/ts-result","commit":"7b6b84e4b6220862ff775ac9da67547d76786aa6"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"25 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T08:39:41.414Z","repository_id":57114908,"created_at":"2025-08-19T08:39:41.414Z","updated_at":"2025-08-19T08:39:41.414Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28340230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["error-handling","generics","result-type","typescript"],"created_at":"2026-01-12T14:02:43.148Z","updated_at":"2026-01-12T14:02:43.337Z","avatar_url":"https://github.com/haideralsh.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![ts-result logo](logo.png)\n\n# ts-result\n\n\u003e A zero-dependency Result type for TypeScript\n\n## Install\n\n```\n$ npm install @haideralsh/ts-result\n```\n\n## Usage\n\nExample adapted from the\n[Elm guide](https://guide.elm-lang.org/error_handling/result.html)\n\n```js\nimport { Result, Ok, Err } from '@haideralsh/ts-result'\n\nfunction isReasonableAge(age: number): Result\u003cnumber, string\u003e {\n    if (age \u003c 0) return Err('Please try again after you are born.')\n    if (age \u003e 135) return Err('Are you some kind of a turtle?')\n\n    return Ok(age)\n}\n\nconst ageResult = isReasonableAge(9000)\n\nif (ageResult.ok === true) {\n    const age = ageResult.get()\n} else {\n    console.error(ageResult.getError()) // Are you some kind of a turtle?\n}\n```\n\n## What is a Result type and why should I use it?\n\nA `Result` type is the result of a computation that may fail. The type is used\nfor returning and propagating errors. It is helpful to give additional\ninformation when things go wrong.\n\n### Example\n\nLet us say that we want to insert a user into our database and return the user\nentity back:\n\n```typescript\nfunction addUser(name: string, email: string): User {\n    const { uuid } = db.query('insert into user values (?, ?)', name, email)\n    return User.getById(uuid)\n}\n```\n\nHowever, an insertion operation can sometimes fail. There is no way for the\ncaller of the function above to know that such failure could happen without\ndiving into the implementation of the function.\n\nWe could handle the potential failure ourselves and return nothing when the\nfailure happens:\n\n```typescript\nfunction addUser(name: string, email: string): User | null {\n    try {\n        const { uuid } = db.query('insert into user values (?, ?)', name, email)\n        return User.getById(uuid)\n    } catch (err) {\n        return null\n    }\n}\n```\n\nIf TypeScript is configured properly, this could be an improvement since\nTypeScript will warn the caller that the result may be `null`. However, it\ndoesn't provide them a way to know what is the error that occurred.\n\nWe can change the null to be a string instead:\n\n```typescript\nfunction addUser(name: string, email: string): User | string {\n    try {\n        const { uuid } = db.query('insert into user values (?, ?)', name, email)\n        return User.getById(uuid)\n    } catch (err) {\n        return err.message\n    }\n}\n```\n\nThis is not any better because now we lose the TypeScript null warning and we\nstill have to check if the returned type is a `string` or a `User` which can be\nnon-trivial.\n\nThis problem becomes more pronounced when both the okay and error results share\nthe same type. Let us say we only want to return the user identifier instead of\nthe whole `User` object:\n\n```typescript\nfunction addUser(name: string, email: string): string {\n    try {\n        const { uuid } = db.query('insert into user values (?, ?)', name, email)\n        return uuid\n    } catch (err) {\n        return err.message\n    }\n}\n```\n\nNow we can not tell if the string returned is the user's UUID or the error\nmessage.\n\nThis is where the `Result` type comes in. It provides a more elegant way for\nhandling potentially erroneous results.\n\nWe can rewrite the above example into this:\n\n```typescript\nimport { Result, Ok, Err } from '@haideralsh/ts-result'\n\nfunction addUser(name: string, email: string): Result\u003cstring, string\u003e {\n    try {\n        const { uuid } = db.query('insert into user values (?, ?)', name, email)\n        return Ok(uuid)\n    } catch (err) {\n        return Err(err.message)\n    }\n}\n```\n\nNow the caller of this function can use the `ok` property to know which type of\nresult is returned\n\n```typescript\nconst insertResult = addUser('Micheal', 'micheal@example.com')\n\nif (insertResult.ok === true) {\n    const userId = insertResult.get() // The user's UUID if the insertion succeeded\n} else {\n    const errorMsg = insertResult.getError() // The error message if the insertion failed\n}\n```\n\n## API\n\n### `Result\u003cT, E\u003e`\n\nA `Result` type accepts two generics. The first (`T`) must match the value type\npassed to `Ok`, while the second (`E`) must match the value type passed to\n`Err`.\n\nA function with a return type `Result` _must_ return either an `Ok` or `Err` or\nboth of them matching their respective types.\n\n```typescript\nimport { Result, Ok, Err } from '@haideralsh/ts-result'\n\nfunction divide(a: number, b: number): Result\u003cnumber, string\u003e {\n    if (b === 0) {\n        return Err('Division by zero!')\n    }\n\n    return Ok(a / b)\n}\n```\n\n#### Properties and functions on a result wrapped with `Ok` or `Err`:\n\nWe can use the `ok` property in order to know if the result was wrapped with an\n`Ok` or an `Err`\n\n#### `ok: boolean`\n\nThe property `ok` will be `true` if a result was wrapped with an `Ok` or `false`\nif it was wrapped with `Err`.\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Ok)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 1)\n\nconsole.log(divideResult.ok) // true\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Err)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 0)\n\nconsole.log(divideResult.ok) // false\n```\n\n\u003c/details\u003e\n\n#### `getOr(defaultValue: any): any`\n\nThe `getOr` function will return the ok value if the result was wrapped with an\n`Ok` or the supplied default value if it was wrapped with `Err`.\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Ok)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 1)\n\nconsole.log(divideResult.getOr('foo')) // 1\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Err)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 0)\n\nconsole.log(divideResult.getOr('foo')) // foo\n```\n\n\u003c/details\u003e\n\n#### `getOrThrow(err?: Error | string): any`\n\nThe `getOrThrow` function will return the ok value if the result was wrapped\nwith an `Ok` or throw an error using the `Err` value as a message. You can\nsupply the error or the error message to throw as an optional parameter.\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Ok)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 1)\n\nconsole.log(divideResult.getOrThrow('foo')) // 1\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Err)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 0)\n\nconsole.log(divideResult.getOrThrow()) // Uncaught Error: Division by zero!\nconsole.log(divideResult.getOrThrow('foo')) // Uncaught Error: foo\nconsole.log(divideResult.getOrThrow(new MyCustomError('foo'))) // Uncaught MyCustomError: foo\n```\n\n\u003c/details\u003e\n\n#### `getOrRun: \u003cS\u003e(fn: () =\u003e S): any`\n\nThe `getOrRun` function will return the ok value if the result was wrapped with\nan `Ok` or run a function if the result was wrapped with an `Err`.\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Ok)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 1)\n\nfunction greeting() {\n    return 'Hello world!'\n}\n\nconsole.log(divideResult.getOrRun(greeting)) // 1\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Err)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 0)\n\nfunction greeting() {\n    return 'Hello world!'\n}\n\nconsole.log(divideResult.getOrRun(greeting)) // Hello world!\n```\n\n\u003c/details\u003e\n\n#### `mapWithDefault\u003cS, R\u003e(defaultValue: S, fn: (parameter: any) =\u003e R): R`\n\nThe `mapWithDefault` function will apply a function on the ok value if the\nresult was wrapped with an `Ok` or the error value if the result was wrapped\nwith an `Err`. The return type will be the same as the supplied function to map.\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Ok)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 1)\n\nfunction addOne(num: number) {\n    return num + 1\n}\n\nconsole.log(divideResult.mapWithDefault(10, addOne)) // 2\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample (Err)\u003c/summary\u003e\n\n```typescript\n// See `divide` implementation above\nconst divideResult = divide(1, 0)\n\nfunction addOne(num: number) {\n    return num + 1\n}\n\nconsole.log(divideResult.mapWithDefault(10, addOne)) // 11\n```\n\n\u003c/details\u003e\n\n### `Ok(value: T)`\n\nThe `Ok` function accepts a value of type `T` that must match the `T` generic\ntype passed to `Result\u003cT, E\u003e`\n\n#### Properties and functions unique to a result wrapped with an `Ok` function:\n\n#### `get(): T`\n\nThe `get` function will unwrap the value wrapped with an `Ok`. You have to check\nif the `ok` property is `true` first before being able to use `get`.\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample\u003c/summary\u003e\n\n```typescript\nconst okResult = OK('foo')\n\nif (okResult.ok === true) console.log(okResult.get()) // foo\n```\n\n\u003c/details\u003e\n\n#### `map: \u003cS\u003e(fn: (parameter: T) =\u003e S): S`\n\nThe `map` function will unwrap and apply the supplied function on the value\nwrapped with an `Ok`. The supplied function must accept the same type as the\nwrapped value type. The return type of the `map` function will be the same as\nthe one of the supplied function. You have to check if the `ok` property is\n`true` first before being able to use `map`.\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample\u003c/summary\u003e\n\n```typescript\nconst okResult = OK('foo')\n\nfunction capitalize(str: string) {\n    return str.toUpperCase()\n}\n\nif (okResult.ok === true) console.log(okResult.map(capitalize)) // FOO\n```\n\n\u003c/details\u003e\n\n### `Err(errorValue: E)`\n\nThe `Err` function accepts a value of type `E` that must match the `E` generic\ntype passed to `Result\u003cT, E\u003e`\n\n#### Properties and functions unique to a result wrapped with an `Err` function:\n\n#### `getError(): E`\n\nThe `getError` function will unwrap the value wrapped with an `Err`. You have to\ncheck if the `ok` property is `false` first before being able to use `getError`.\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample\u003c/summary\u003e\n\n```typescript\nconst errResult = Err('foo')\n\nif (errResult.ok === false) console.log(errResult.getError()) // foo\n```\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaideralsh%2Fts-result","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaideralsh%2Fts-result","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaideralsh%2Fts-result/lists"}