https://github.com/yawaramin/prometo
A type-safe JavaScript promise library for ReasonML
https://github.com/yawaramin/prometo
bucklescript ocaml reasonml
Last synced: about 1 year ago
JSON representation
A type-safe JavaScript promise library for ReasonML
- Host: GitHub
- URL: https://github.com/yawaramin/prometo
- Owner: yawaramin
- Created: 2019-12-08T03:50:52.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2020-09-28T02:41:43.000Z (over 5 years ago)
- Last Synced: 2025-04-24T23:04:19.125Z (about 1 year ago)
- Topics: bucklescript, ocaml, reasonml
- Language: Reason
- Homepage: https://yawaramin.github.io/prometo/
- Size: 47.9 KB
- Stars: 31
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
## Prometo
[](https://npmjs.org/package/@yawaramin/prometo)
[](https://dev.azure.com/yawaramin/prometo/_build/latest?definitionId=1&branchName=main)
A type-safe promise type for ReasonML, built directly on top of
JavaScript but adding fine-grained error control and promise
cancellation.
## How it works
Prometo is type-safe because of the following:
- It's not just a 'promise of your data', it's a 'promise of result of
your data'. In other words, it can't be affected by JavaScript
promises' well-known unsoundness issue where a 'promise of promise of
data' is collapsed at runtime to a 'promise of data'.
- Also because a Prometo promise is a 'promise of result of data', it
encodes an error at the type-level using the Reason `result('a, 'e)`
type. In fact, Prometo ensures that its wrapped promises are not
rejected, as long as you use its operations. So you can be sure that a
Prometo promise is actually not going to throw at runtime. The only
point at which you need to care about catching a possible exception is
when converting it back into a normal JavaScript promise.
Because it's just a JavaScript promise wrapper, it's also easy to
convert back and forth between JavaScript and Prometo promises.
## Fine-grained error management
Using the technique described in
[Composable Error Handling in OCaml](https://keleshev.com/composable-error-handling-in-ocaml),
Prometo exposes an error type `'e` directly in its main polymorphic
promise type `Prometo.t('a, 'e)`. This allows you to explicitly track
and manage errors at every point of the code where you use these
promises.
## Interoperability
It's easy to interop with JavaScript promises:
- Use `fromPromise` to convert from a JavaScript Promise to a Prometo
promise
- `toPromise` to convert from Prometo to a JavaScript promise
- `thenPromise` to chain together a Prometo promise and a function that
returns a JavaScript Promise, and keep the result as a type-safe
Prometo promise.
## Cancellation
Prometo promises can be cancelled at any point of usage in the code,
using `Prometo.cancel`. The only caveat is that when you cancel a
promise, it doesn't _immediately_ halt whatever is running inside that
promise, but lets it run until its result is used by the next `flatMap`
in the promise chain. At that point, the _next_ promise automatically
turns into a cancelled promise, stopping whatever was about to happen
next from happening.
This also does mean that if you want to cancel a promise chain, you need
to ensure that you keep a reference to the _first_ promise in the chain
and cancel _that._
While not as immediate as something like
[abortable fetch](https://developers.google.com/web/updates/2017/09/abortable-fetch),
in practice this is more general-purpose (it works with any promise, not
just ones returned by `fetch`), and it's enough to prevent errors like
[calling `setState` on an unmounted React component](https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html).
For example:
```reason
let example = fetch("https://example.com");
Prometo.forEach(~f=setState, example);
// later...
Prometo.cancel(example); // this will prevent setState from being called
```
Cancelling a promise too late in the chain won't work:
```reason
let result = "https://example.com"
|> fetch
|> Prometo.map(~f=setState);
// later...
Prometo.cancel(result); // won't work, too late, setState has already been called
```
## Add to project
- Add the `@yawaramin/prometo` project to your `package.json` (version
number in badge at the top of the readme)
- Add the `@yawaramin/prometo` dependency to your `bs-dependencies` list
in `bsconfig.json`
- Run `npx bsb -clean-world`, then `npx bsb -make-world`
- (Optional but
[recmomended](https://dev.to/yawaramin/consuming-a-modular-ocaml-project-structure-1a2e))
if you don't have one already, create a `Yawaramin.re` (or `.ml`) file
under `src/` and alias the Prometo main module there:
`module Prometo = Yawaramin__Prometo`. This lets you access it under
the `Yawaramin.Prometo` namespace throughout your project
## API docs
Please go to https://yawaramin.github.io/prometo/