{"id":13622401,"url":"https://github.com/option-t/option-t","last_synced_at":"2025-04-15T06:30:25.538Z","repository":{"id":28569741,"uuid":"32087446","full_name":"option-t/option-t","owner":"option-t","description":"A toolkit of Nullable/Option/Result type implementation in ECMAScript. Their APIs are inspired by Rust's `Option\u003cT\u003e` and `Result\u003cT, E\u003e`.","archived":false,"fork":false,"pushed_at":"2025-03-26T09:44:44.000Z","size":10171,"stargazers_count":303,"open_issues_count":26,"forks_count":6,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-26T10:32:54.863Z","etag":null,"topics":["javascript","nullable","option-type","result-type","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/option-t","language":"JavaScript","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/option-t.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.MIT","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}},"created_at":"2015-03-12T16:20:09.000Z","updated_at":"2025-03-26T09:44:47.000Z","dependencies_parsed_at":"2023-01-16T22:16:53.018Z","dependency_job_id":"2df7a8db-3e99-4e01-b5aa-750e0bab0b37","html_url":"https://github.com/option-t/option-t","commit_stats":{"total_commits":2080,"total_committers":10,"mean_commits":208.0,"dds":0.5192307692307692,"last_synced_commit":"7f786b5864376fa85e7f002cc9d4785a7fec76b6"},"previous_names":[],"tags_count":340,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/option-t%2Foption-t","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/option-t%2Foption-t/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/option-t%2Foption-t/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/option-t%2Foption-t/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/option-t","download_url":"https://codeload.github.com/option-t/option-t/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249020568,"owners_count":21199581,"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":["javascript","nullable","option-type","result-type","typescript"],"created_at":"2024-08-01T21:01:18.680Z","updated_at":"2025-04-15T06:30:25.529Z","avatar_url":"https://github.com/option-t.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# option-t\n\n[![npm](https://img.shields.io/npm/v/option-t.svg?style=flat)](https://www.npmjs.com/package/option-t)\n[![CI on main branch](https://github.com/option-t/option-t/actions/workflows/ci_on_main.yaml/badge.svg)](https://github.com/option-t/option-t/actions/workflows/ci_on_main.yaml)\n\n* **This library provides a toolkit for _nullable_ types in ECMAScript**.\n    - `T | null`\n    - `T | undefined`\n    - `T | null | undefined`\n    - [_Result type_](https://en.wikipedia.org/wiki/Result_type)\n    - Tagged [_Option type_](https://en.wikipedia.org/wiki/Option_type)\n* **APIs are inspired by Rust Language's [`Option\u003cT\u003e`](https://doc.rust-lang.org/std/option/) and [`Result\u003cT, E\u003e`](https://doc.rust-lang.org/std/result/)**.\n* **This library helps to sort the \"nullable\" convention in your project**.\n* **TypeScript friendly APIs**.\n    * We recommend to use this with some static type systems like TypeScript.\n* **Zero dependency**.\n    * We use only a pure [ECMAScript](https://tc39.es/ecma262/) feature to implement this library as possible\n      except a packaging system or a legacy module system.\n    * This library is designed to be portable to any [host environments](https://tc39.es/ecma262/#host-environment)\n      supporting a set of ECMAScript features which we use, _at implementation code level (not at packaging level)_.\n    * We might provide a feature using [host defined](https://tc39.es/ecma262/#host-defined) facilities\n      but they would be a __opt-in__.\n* **Tree shakable completely**.\n* **ES Module first**.\n    * Don't worry. We have a compatibility for _require(esm)_ of Node.js. \n* **Enable to use with a programming styles that mixes an execution context between server and client across the boundary (e.g. [Qwik](https://github.com/BuilderIO/qwik)).**\n\n\n## Motivation\n\nThis library provides these conventions for your project:\n\n1. Uniform an expression of _\"none\"_ value in JavaScript.\n2. Uniform a way to carry error information instead of throwing an error by _result type_.\n3. Provide various utility functions to handle _1_ and _2_ easily.\n\nAnd Rust's [`std::option`](https://doc.rust-lang.org/std/option/) and [`std::result`](https://doc.rust-lang.org/std/result/) are\nsuggestive to achieve these conventions in practice. Thus this package is inspired by their design.\n\n\n### Uniform the expression of \"none\" value.\n\nIn JavaScript world, there are many ways to express \"there is no value\".\nAt least in ECMA262, There are some ways to represent them:\n\n* `undefined` (e.g. `Map.prototype.get()`)\n* `null` (e.g. `RegExp.prototype.exec()`)\n* `-1` (e.g. `String.prototype.indexOf()`)\n\nIn addition, ECMA262 interacts with [DOM binding](https://heycam.github.io/webidl/),\nNode.js standard modules, and others. There are additional various ways to represent \"none\" value.\n\nIn practice, we write some _glue code_ to tame their various ways in our project to uniform their expression style.\nThis library contributes to uniform the convention to write it.\n\n\n### Uniform the way to carry error information instead of throwing an error.\n\n_Exception_ is useful but it has some terrible aspects.\nIt's easy that _try-catch_ statement to be a jump instruction by large scoped _try-catch_ statement.\nIt's hard to find where to throw an error, it's also hard to handle a penetrated exception from a lower layer.\nEspecially, _exception_ mechanism mis-matches with an async programming model.\nECMA262 7th' _async-await_ relaxes the problem about an exception with async programming,\nbut there is still the problem about exceptions in traditional synchronous programming.\nFurthermore, if you interact with `setTimeout()` and other async APIs built with callback style on event loop,\nthis problem faces you.\n\nAnd some async-push based paradigm like `Rx.Observable\u003cT\u003e` does not allow throw any exceptions\nin their _Observable_ stream. If you throw an error in it, only _catch()_ operator can catch the error.\nBut a programmer would sometimes forget to use its operator. This means that throwing an Error in Rx's _Observable_\nis pretty mis-matched action. _Promise\u003cT\u003e_ also has a similar problem.\n\nAnd exception in ECMA262 is not friendly with static typing model\nbecause ECMA262's _throw_ can throw not only `Error` but also other object types.\n\nIn Rust which is a programming language designed for parallel and seftiness, it treats errors in two category:\n\n\u003e Rust groups errors into two major categories: _recoverable_ and _unrecoverable_ errors.\n\u003e For a recoverable error, such as a file not found error,\n\u003e it’s reasonable to report the problem to the user and retry the operation.\n\u003e Unrecoverable errors are always symptoms of bugs, like trying to access a location beyond the end of an array.\n\nThis categorization is pretty useful to relax the problem about exception in ECMA262 which this section described.\n\nThus this library provides a way to express _recoverable_ error and also recommends\nto use throwing an error only if you intend to throw an _unrecoverable_ error.\nThis categorization introduces a convenient convention for you:\n\n* If the code uses _throw_, you should be careful about _unrecoverable_ error.\n* If the code returns `Result\u003cT, E\u003e` provided this library, then you should handle it correctly.\n\nThis convention is clear as error handling style and it's static typing friendly by _generics_.\n\n\n### Provide a utility function to handle these uniformed expression easily.\n\nSome static type checking tools also provide a way to check nullability and provide these conventions.\n\n- Flowtype's semantics has [a built-in \"Maybe\" types](https://flow.org/en/docs/types/maybe/),\n- TypeScript has [a non-nullable type check](https://github.com/Microsoft/TypeScript/issues/185),\n- Google Closure Compiler also can check a non-nullable type via JSDoc style annotations in some compilation mode.\n\nFlowtype and TypeScript checks with their control flow analysis\n(Sorry, I'm not sure about the details of Google Closure Compiler's behavior).\n\nHowever, these compilers do not provide a way to handle their value easily like `map` or `flatMap` operations.\n\nRust's `std::option` and `std::result` have some utility operation methods to handle them easily.\nThis library also provides a convenient way to handle them and its way is inspired by Rust's ones.\n\n\n\n## Supported Environments\n\nWe target to run in following environments.\n\n- Language\n    - [ECMA262 2017 edition](https://262.ecma-international.org/8.0/).\n    - TypeScript's latest version.\n- Module system\n    - ES Module ([ES2020](https://262.ecma-international.org/11.0/) level).\n        - We have a compatibility with [_require(esm)_](https://nodejs.org/docs/latest-v22.x/api/modules.html#loading-ecmascript-modules-using-require) for Node.js.\n    - A runtime environment or module bundler must support Node.js' [package.json's `exports` field](https://nodejs.org/api/packages.html#package-entry-points) (Newer is better).\n        - We require TypeScript's [`--moduleResolution`](https://www.typescriptlang.org/tsconfig/#moduleResolution)\n          is set as `node16`, `bundler`, or others that supports `exports` field if your project use TypeScript.\n\n\n### Caution\n\n- Your code may work with this package even if your project does not supports all of these requirements.\n  But we may not be able to support such environments officially. We recommend to update your environment generally.\n\n\n\n## Installation\n\n```sh\nnpm install --save option-t\n```\n\nFor more details, please see [docs/installation.md](./docs/installation.md).\n\n\n\n## Usage \u0026 APIs\n\nThese are designed for more tree shaking friendly and more usable for JavaScript common world,\nand all APIs are TypeScript ready.\n\n* _Utility functions for these types_.\n    * [`Nullable\u003cT\u003e` (`T | null`)](./docs/public_api_list.md#nullable)\n    * [`Undefinable\u003cT\u003e` (`T | undefined`)](./docs/public_api_list.md#undefinable)\n    * [`Maybe\u003cT\u003e` (`T | null | undefined`)](./docs/public_api_list.md#maybe)\n    * plain objects as tagged union.\n        * [`Result\u003cT, E\u003e` (`{ ok: true; val: T } | { ok: false; err: E; }`)](./docs/public_api_list.md#plainresult)\n        * [`Option\u003cT\u003e` (`{ ok: true; val: T } | { ok: false; }`)](./docs/public_api_list.md#plainoption) (_deprecated_)\n\nAdditional documents are in [`docs/`](./docs/).\n\n\n### How to import\n\n#### Examples\n\n```ts\n// Import functions and types which you would like to use:\nimport { type Maybe } from 'option-t/maybe';\nimport { type Nullable, isNotNull } from 'option-t/nullable';\nimport { type Undefinable } from 'option-t/undefinable';\nimport { type Result, createOk, isOk } from 'option-t/plain_result';\n```\n\n```ts\n// You can also use `\u003cTypeName\u003e.\u003coperatorName\u003e`\nimport { Nullable } from 'option-t/nullable/namespace';\n\ndeclare let numberOrNull: Nullable.Nullable\u003cnumber\u003e;\n// IntelliSense can suggest and narrow down by the order of Type -\u003e related operations.\nconst some = Nullable.unwrapOr(numberOrNull, -1);\n```\n\n```ts\n// You can import only a specific function by the more detailed path.\nimport { type Nullable, unwrapNullable } from 'option-t/nullable/nullable';\nimport { unwrapOrForNullable } from 'option-t/nullable/unwrap_or';\n```\n\n#### See also\n\n**You can import [these paths in the list of public APIs](./docs/public_api_list.md).**\nThis package provides some sub directories to import various functions (e.g. `option-t/PlainResult`).\n\nIf you're project cannot import by their path, please read [our installation guide](./docs/installation.md) to know more details.\n\n\n### Deprecation\n\nAll deprecated items including \"not recommended\" are marked as `@deprecated` in JSDoc.\nPlease read [this guide](./docs/deprecated_apis.md) to know more details.\n\n\n## See also\n\nThese documents would provide more information about `Option\u003cT\u003e` and `Result\u003cT, E\u003e`.\nThese are written for Rust, but the essence is just same.\n\n- [Error Handling - Rust by Example](https://doc.rust-lang.org/rust-by-example/error.html)\n- [Error Handling - The Rust Programming Language](https://doc.rust-lang.org/book/second-edition/ch09-00-error-handling.html)\n- [`std::option` - Rust](https://doc.rust-lang.org/std/option/)\n- [`std::result` - Rust](https://doc.rust-lang.org/std/result/)\n\n\n\n\n## License\n\n[MIT License](./LICENSE.MIT)\n\n\n\n\n\n\n## Contribution\n\n- Use npm v9 or later to install dev-dependency toolchains.\n\n\n\n## Related works: Comparison with other similar packages\n\n### [fp-ts (v2.13.1)](https://github.com/gcanti/fp-ts/tree/2.13.1)\n\n_fp-ts_ is a package that provides various tools to write a functional programming style code including _Either_ and _Option_ type.\n\nOur design’ origin is Rust language, so we also contains an essence of functional programming style which Rust language contains.\nIn this point, features that we provide would be similar to fp-ts’ one.\n\nHowever, we do not aim to provide a feature to write a functional programming language code unlike fp-ts.\nOur design goal is that we provide more specialized tools to handle an absence of values.\n\nWe think **[Effect-TS (v3.1.0)](https://github.com/Effect-TS/effect/tree/effect%403.1.0)** is also placed in here.\nSide-effect handling abstraction, concurrency controls, or platform integration are not a goal of this package.\nWe intend to provide only value types that are evaluated immediately unlike them. \n\n\n### [neverthrow (v8.1.1)](https://github.com/supermacro/neverthrow/tree/v8.1.1)\n\n_neverthrow_ is a package that provides _Result_ type implementation.\nAt this point, we think that we and they share the same spirits.\n\nHowever, we think there are some different design decisions between neverthrow and us.\n\n\n#### option-t does not provide a method chain style but have a perfect \"tree-shakability\"\n\nWe do not provide class based implementation and method chaining style.\nHistorically, we had provided a method-chain style APIs and data types as tier 1.\n\n- [`ClassicOption`](./packages/option-t/src/deprecated/classic_option/classic_option.ts)\n- [`ClassicResult`](./packages/option-t/src/deprecated/classic_result/classic_result.ts)\n\nBut we gave up method chain style as primary style and switched our primary APIs\nto current simple functions combination style for various reasons.\n\nFirst, there was a problem with [dead code elimination](https://en.wikipedia.org/wiki/Dead-code_elimination).\nDead code elimination (as known as DCE or “tree shaking” in JavaScript toolchain context) is important optimization.\nIt reduces a final bundled code size after linking codes by a module bundler (linker).\n\nHowever, it’s hard to remove unused object property methods in JavaScript.\nTo remove them _safely_, an optimizer should know whether an object property is used or not over a whole of programs.\nBut this kind of optimization requires perfect call graph information too.\nThis kind of optimization is easy relatively with a static language like C++ or Rust\nbut JavaScript is a dynamic language essentially.\nJavaScript has a multiple way to prevent a this kind of optimization like a reflection (e.g. `Object.keys(obj)`).\nSo it’s hard.\n\nUnder this condition, we cannot add a feature as property methods without increase the final code size.\nWe would like to add a popular feature as a part of this package to reuse it or would like to fill a gap with Rust's original feature set.\nBut a user project does not use all features at all times.\nThey use a partial of this package generally. Even if an user project does not use them,\nfeatures provided as an object property method are not removed, so it increases a final application size.\nThis might be a big problem for client-side applications, especially to implement SDK libraries.\nThus we would like to avoid it sincerely.\n\nExceptionally, as our memory, Google Closure Compiler’s advanced optimization mode can do such aggressive dead code elimination\nabout an unused object property as a part of static optimization.\nBut it’s not a popular toolchain choice in the 2010s later.\nWe could not expect that a user project accept it as a popular choice rather than UglyfyJS, terser,\nor other code minifier lacking an analysis whole of programs statically.\n\nSecond, there was a problem with TypeScript’s type inference.\nIn 2016~2018, our method chain style implementation sometimes fall into that\na type parameter for generics fallback to `any` or `unknown`\nin the middle of a long (relatively complex) method chain in our user project.\nThis causes to break a type integrity whole of a project and causes a bad developer experience.\n\nThird, there was a problem making it hard to keep a consistent behavior with mixing multiple versions in a project dependency.\nA class based object implementation often supports `instanceof` check naturally as a part of APIs implicitly.\nHowever, if there are multiple versions of same name package in a project dependencies\nby aggregating them with semantic versioning, `instanceof` behavior might be inconsistent as contrary to expectations of a developer.\n\nFor example,  the following code will result as `false`. This is just unsound.\n\n```js\n// This is some_package@v2 actually.\nimport { SomeClass } from 'some_package';\n// This package uses some_package@v1 as dependency.\nimport { getBar } from 'other_package';\n\n// This value is some_package@v1's instance\n// that have the same type shape with some_package@v2's same named class instance.\nconst bar = getBar();\n// Developers think this should be `true`, but the actual is `false`.\nconsole.log(bar instanceof SomeClass); // false\n```\n\nYou may think TypeScript’s static type system can fix this problem,\nbut it cannot do. TypeScript’s type system uses structural subtyping.\nThis example is valid if the `bar`  and `SomeClass`  (instance) have the same type shape.\nAs a result, it’s bad behavior. To fix above problems,\nwe gave up method chain style and made it deprecated.\n\nFourth, a new programming style for web application in JavaScript is emerging that\nmixes a code execution context either with a client or a server  (e.g. [Qwik](https://github.com/BuilderIO/qwik)).\nWith their style, each of objects are required to be serializable to allow to transfer a data\nfrom the server to the client across boundaries. We cannot use method chains in such a case.\n\nFinally, we shifted to provide a set of minimum types and various standalone \"operator\" functions.\nThis design allows us to \"tree-shaking\" perfectly to remove unused functions.\n\nOf course, we know this design style is a boring programming style.\nIf [pipeline operator proposal](https://github.com/tc39/proposal-pipeline-operator) advance to the part of ECMA262 spec,\nthis boring style problem might be relaxed.\n\nFurthermore, we think that it happens many times reading the code but writing one is fewer than it.\nWe believe that this style is tiring but not a problem in the long term.\n\n#### option-t does not provide [`try!`](https://doc.rust-lang.org/1.83.0/std/macro.try.html) like control flow sugar utility to keep a simplicity of user project code\n\nWe got some feedbacks about why option-t does not provide a `try!` like control flow sugar function\nto make it easy to unwrap of `Result\u003cT, E\u003e` type.\nAnd some users told us that they switched to _neverthrow_ that have [`safeTry()`](https://github.com/supermacro/neverthrow/tree/v8.1.1?tab=readme-ov-file#safetry)\ndue to lacking a such function in this package by default. \n\nIn short, this is a result of design choice.\nWe would hesitate to do it or will not implement such utility sugaring stuff\nwithout introducing a macro system to JavaScript.\n\nUnlike a syntax expansion achieved by macro, the kind of `try!` utility uses a generator mechanism\nlike an emulation of async/await style control flow in pre-ES2017 era.\n\nWe admit it simplifies a control flow related to unwrap operation for Result type\nbut we think it introduces a complication to a user code.\nThis means that user code gets a new userland executor mechanism in addition to a react fiber or other view library's runtime executor.\nWe think it might be hard to debug a code that lives a long time (probably over a decade)\nbecause such code requires an additional knowledge of this library's framework-ish practice.\n\nOur motto of design \u0026 implementation is that achievement both of simplicity and abstraction.\nWe think this design choice is important to keep a simplicity of code analytic pipeline,\na simplicity of build pipeline, and to reduce a runtime overhead of user project application for long-term user project code lifecycle.\nTherefore we would like to avoid introducing a new sugar utility that is a bit different from a common control syntax flow populated\nin the community to decrease complexity by introducing this library.\nWe think strongly that \"writing a code is only once, but your code will be read far many times than what you imagined\".\n\nIf you want `try!` style utility,\nplease consider to introduce [option-t-safe-try](https://jsr.io/@totto/option-t-safe-try) ([github](https://github.com/totto2727-org/option-t-safe-try))\nor defines a similar implementation to your repository. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foption-t%2Foption-t","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foption-t%2Foption-t","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foption-t%2Foption-t/lists"}