I’ve been working on this for a little over a month, wrote a couple of articles and tried to share it around without much luck so I figured I’d try again. I just released v0.3.10, which I’m treating as the first stable release. No further breaking changes are planned for the API surface so now is a good time to take a look.
Aljabr is a zero-dependency TypeScript library that treats tagged unions (algebraic data types) as the central primitive. You define a union once and get exhaustive pattern matching, schema validation, and reactive state management all from that single definition. The problem it solves is the fragmentation that happens when domain models, validation, and reactivity are handled by separate libraries. By unifying everything around unions, it makes application state behave like a compiler-checked finite state machine and eliminates whole categories of impossible-state bugs.
This an example from the Readme that demonstrates perfectly what I mean:
/** @jsxImportSource aljabr/ui/dom */
import { union, match, type Union } from "aljabr";
import { Store, Derived } from "aljabr/prelude";
import { createRenderer } from "aljabr/ui";
import { domHost } from "aljabr/ui/dom";
const Shape = union({
Circle: (id: number, radius: number) => ({ id, radius }),
Rect: (id: number, w: number, h: number) => ({ id, w, h }),
});
type Shape = Union<typeof Shape>;
const area = (s: Shape) => match(s, {
Circle: ({ radius }) => Math.PI * radius ** 2,
Rect: ({ w, h }) => w * h,
});
const shapes = Store.create<Shape[]>([Shape.Circle(1, 5), Shape.Rect(2, 3, 4)]);
const total = Derived.create(() => shapes.reduce((sum, s) => sum + area(s), 0));
const rows = shapes.map(
s => <li>{area(s).toFixed(2)}</li>,
{ key: s => s.id },
);
const { mount } = createRenderer(domHost);
mount(() =>
<div>
<ul>{rows}</ul>
<p>Total: {() => total.get()?.toFixed(2)}</p>
<button onClick={() => shapes.push(Shape.Circle(Date.now(), 10))}>
Add Circle
</button>
</div>,
document.body,
);
What’s in the box:
- Tagged unions with
match(),is.*wildcards,select()extraction -
Result,Option,Validation,Signal,Derived,Store,List,Resource,Dispatcher,Scope - Schema decode/encode pipeline where errors surface as a
Validationunion - SolidJS-flavored reactive primitives and a pluggable UI layer (DOM + Canvas renderers)
Live CodeSandbox demo (no install needed): https://codesandbox.io/p/devbox/aljabr-demo-vtlr6t
Note: CodeSandbox's iframed browser screws with the canvas coordinates (I've already tracked this bug for future development) but, to use the demo fully, press the "Open in a new tab" button to normalize things.
If you prefer to run it locally: git clone the repo and npm run dev (or whatever package manager you use).
v0.3.10 (stable) release notes: https://github.com/jasuperior/aljabr/releases
Repo: https://github.com/jasuperior/aljabr
I’d love any kind of feedback, questions, bug reports, or even just a star if you like the idea.
Top comments (0)