From 02013a25d2c6b5a5fbe7b8e0a072b67d25165ee8 Mon Sep 17 00:00:00 2001 From: Sergey Slipchenko Date: Thu, 8 Feb 2024 09:46:01 +0400 Subject: [PATCH] fix: add a README.md --- README.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..df503e8 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# @faergeek/monads + +Easy to use monads for JavaScript and TypeScript. + +Source code itself is pretty small, but it has jsdoc comments, which should +serve as a more complete API documentation: + +- [Maybe](./src/maybe.ts) + + An abstract box representing either presence or absence of a value. + + A box with a value can be created with `Maybe.Some()`. `Maybe.None` + represents an absence of a value. + + Read the comments in source file linked above for details. + +- [Async](./src/async.ts) + + An abstract box representing asynchronous value state. Very similar to + `Maybe`, but has less operations. It exists to make sure that + presence/absence of a value and pending/ready state are easy to tell apart. + Very useful to convey loading state through any value transformations. + + A box with a value ready to be used can be created with + `Async.Ready()`. `Async.Pending` represents a pending state meaning + there's no value yet. + + Read the comments in source file linked above for details. + +- [Result](./src/result.ts) + + An abstract box representing success or failure. + + A box representing success can be created with `Result.Ok()`. + A box representing failure can be created with `Result.Err()`. + + Read the comments in source file linked above for details. + +An example of using both `Async` and `Result` to represent different states of +UI depending on API request result from a hook like SWR or React Query. + +First, we need to create a box, representing 3 states: pending, success and +failure. + +```javascript +// let's assume data is something like a number 21 +const { data, error, isLoading } = useSomeApiHook(); + +const halfTheAnswer = data + ? Async.Ready(Result.Ok(data)) + : isLoading + ? Async.Pending + : Async.Ready(Result.Err(error)); +``` + +Then apply transformations with `map*` or `flatMap*` functions. + +Here we simply multiply the value by 2. But the same approach can be used to extract +only some pieces of response data, transform them and pass to child components, +all without loosing request state attached to it. + +```javascript +const theAnswer = halfTheAnswer.mapReady( + // this function is only called if `halfTheAnswer` represents ready state + result => + result.mapOk( + // this function is only called if `result` represents success state + x => x * 2, + ), +); +``` + +And finally use the value, explicitly handling all cases. In this example, we +simply render a piece of UI with something like React. + +```javascript +return theAnswer.match({ + Pending: () =>

Fetching the answer, please wait...

, + Ready: result => + result.match({ + Err: error =>

Could not get the answer: {error.message}

, + Ok: data =>

The Answer is {data}

, + }), +}); +```