UNPKG

twitten

Version:

A fluent js/ts implementation of the result monad, utilizing Happy/Sad path terminology.

94 lines (66 loc) 4.06 kB
## Twitten - type safe & expressive error-handling [![Build Status](https://travis-ci.org/Kusken/Twitten.svg?branch=master)](https://travis-ci.org/Kusken/Twitten) [![Read the Docs (version)](https://img.shields.io/readthedocs/pip/stable.svg)](https://kusken.github.io/Twitten/modules/_index_.html) [![GitHub license](https://img.shields.io/github/license/Kusken/Twitten.svg)](https://github.com/Kusken/Twitten/blob/master/LICENSE) [![NPM](https://nodei.co/npm/twitten.png)](https://nodei.co/npm/twitten/) ## Problems solved - Type-safe error-handling for JS & TS - Ubiquitous language for error-handling ## Introduction The twitten library lets you handle errors in JavaScript and TypeScript in a **type safe** and **expressive** way. The way this is done is nothing new, especially if you're familiar with how success and error cases are handled in the functional world. What's unique as far as I know is that this little library utlize _'Happy & Sad path'_ temrinology drawn from the world of testing. ## Examples ### How we usually do when we only have the try/catch + throw jump statement ```typescript function createUser(uname: string, pw: string): User { if (!(uname && pw)) throw new Error("Validation failed!"); return { username: uname, password: pw }; } try { const user = createUser("John Doe", "hello123"); console.log(user.username, user.password); } catch (error) { throw error; } ``` #### CONS - This approach makes our code harder to reason about than it has to be. Since js and ts does not allow us to embedd the _throw_ **jump statement** in our function and method signatures, we have to rip up the hood and read the **implementation details** for clues to what errors we could handle. - There's more to it than that! Like other jump statements the **throw** statement makes the control flow of our applications harder to reason about. The control flow following an expected path from **module** `a -> b -> c...` is disturbed. We could have the control go from **module** `a -> d...` or `a -> b -> c -> g -> p -> x..-`. There are many possibilites, and its **hard to reason about!** - Adding to the stack of _hard to_ reasons, js and ts doesn't have the **powerful catch** clause that we know from languages like C#. ### The Altenrative - `import { Path, Happy, Sad } from "twitten"` #### Path with explicit type checking & unwrap ```typescript function createUser(uname: string, pw: string): Path<User> { if (!(uname && pw)) return Sad.path(new Error("Something went wrong!")); return Happy.path({ username: uname, password: pw }); } //Must do explicit type checking before we know the correct type of outcome const user = createUser("John Doe", "hello123"); if (Path.isHappy(user.outcome)) console.log(user.outcome.username, user.outcome.password); else //outcome.message refers to 'Error.message' console.log(user.outcome.message); ``` #### Path with continuations ```typescript const user = createUser("John Doe", "hello123"); user.onHappyPath(usr => console.log(usr.username, usr.password)) .onSadPath(error => console.log(error.message)); ``` #### Path with more continuations ```typescript const user = createUser("John Doe", "hello123"); user.onHappyPath(usr => { console.log(usr.username, usr.password); return usr; }).onHappyPath(usr => usr.username.replace(" ", "_")) .onHappyPath(uname => console.log(uname)); ``` #### Conclusion By embedding errors within the type system, we force awarness of potential failures upon consumers of our code. By doing so we make a clear distinction between _**unexpected**_ and _**exceptional**_ errors (exceptions) on one side, and _**expected**_ errors (sad paths) on the other. If an exception bubbles up to the end-user it will not have anything to with the expected like a input validation error, so we know that something went seriously wrong. ## For documentation see - [Tests](https://github.com/Kusken/Twitten/blob/master/tests/Path.spec.ts) - [Docs](https://kusken.github.io/Twitten/index.html)