An algebraic effects library for javascript and typescript using generators
Algebraify
Algebraic Effects Are Here! (sort of)
(If you’re unfamiliar with algebraic effects, here’s a great article: Algebraic Effects for the Rest of Us)
This is a single-goal library that utilizes generators to add algebraic effects to javascript and typescript.
Usage
Add it to your project by using npm install algebraify
or yarn add algebraify
, in case you didn’t know.
Examples
Javascript
sync:
import algebra from "algebraify";
const getUser = algebra(function* getUser(_, id) {
const name = getNameOfUser(id) ?? (yield "name");
const age = getAgeOfUser(id) ?? (yield "age");
return `USER ${name}: ${age} years old`;
});
const userString = getUser(100)
.case("name", "John Smith")
.case("age", 18)
.do();
// userString will fallback to using the name john smith and the age 18 if those respective calls fail
async:
// Just change to an async generator function
const getUser = algebra(async function* getUser(_, id) {
const name = await getNameOfUser(id) ?? (yield "name");
const age = await getAgeOfUser(id) ?? (yield "age");
return `USER ${name}: ${age} years old`;
});
// And then await the promise returned by do()
const userString = await getUser(100)
.case("name", "John Smith")
.case("age", 18)
.do();
Typescript
import algebra from "algebraify";
const getUser = algebra(function* getUser(request, id: number) {
// Note the calls to request and subsequent calls to as
const name = getNameOfUser(id) ?? (yield* request("name").as<string>());
const age = getAgeOfUser(id) ?? (yield* request("age").as<number>());
return `USER ${name}: ${age} years old`;
});
const userString = getUser(100)
.case("name", "John Smith")
.case("age", 18)
.do();
// userString will have the type `USER: ${string}: ${number} years old`
// Async changes are identical in ts
The request parameter is a function that returns a narrowly typed iterator. You don’t need to know the details of how it works to use it; yield* request("name").as<string>()
is basically the same as doing yield "name"
, but using some type magic to tell typescript to trust us on the return type.
Contributing
Please contribute! I’ve never made a library that I wanted other people to use before, and my experience with JS/TS is small compared to my programming career. I’d appreciate it a ton!