https://github.com/zrosenbauer/massaman
Functional programming utilities for TypeScript. Result types, pattern matching, async pipelines.
https://github.com/zrosenbauer/massaman
es-toolkit functional-programming pattern-matching result-type ts-pattern typescript
Last synced: 25 days ago
JSON representation
Functional programming utilities for TypeScript. Result types, pattern matching, async pipelines.
- Host: GitHub
- URL: https://github.com/zrosenbauer/massaman
- Owner: zrosenbauer
- License: mit
- Created: 2026-05-13T00:20:14.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-05-15T22:03:20.000Z (28 days ago)
- Last Synced: 2026-05-16T00:40:31.638Z (28 days ago)
- Topics: es-toolkit, functional-programming, pattern-matching, result-type, ts-pattern, typescript
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/massaman
- Size: 1.7 MB
- Stars: 3
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
Functional programming utilities for TypeScript. Result types, pattern matching, async pipelines. Fully typed.
## Features
- Rust's `match` in TypeScript: exhaustive pattern matching via re-exported [ts-pattern](https://github.com/gvergnaud/ts-pattern).
- Rust's `Result` in TypeScript: compose fallible operations without throws (`attempt`, `attemptAsync`, `ok`, `err`, `isOk`, `unwrap`).
- Functional programming, fully typed: `flow`, `flowAsync`, `tap`, `when`, `ifElse`, and point-free combinators with end-to-end inference.
- The missing pieces around [es-toolkit](https://es-toolkit.dev): variadic-narrowing predicates, async composition, and consistent error normalization on top of the array/object/string/math utilities you already love.
- Tree-shakeable: 12 focused subpath exports, ESM-only, `sideEffects: false`. Import only what you use.
## Install
```bash
npm install massaman
```
## Usage
### From ts-pattern
The `pattern` subpath is a transparent re-export of [ts-pattern](https://github.com/gvergnaud/ts-pattern). Exhaustive matching with full TypeScript inference.
```ts
import { match, P } from 'massaman/pattern'
const status = match(action)
.with({ type: 'load' }, () => 'loading')
.with({ type: 'success' }, () => 'done')
.with({ type: 'error', msg: P.string }, ({ msg }) => `failed: ${msg}`)
.exhaustive()
```
### From es-toolkit
Most of the surface (`array`, `object`, `string`, `function`, `math`) is a transparent re-export of [es-toolkit](https://es-toolkit.dev). Same names, same behavior, same docs.
```ts
import { chunk, groupBy } from 'massaman'
chunk([1, 2, 3, 4, 5], 2)
// [[1, 2], [3, 4], [5]]
groupBy(['apple', 'avocado', 'banana', 'blueberry'], (s) => s[0])
// { a: ['apple', 'avocado'], b: ['banana', 'blueberry'] }
```
### Custom: Result and async composition
Built on top of those re-exports, `massaman/control` adds Result-style error handling that never throws across a boundary.
```ts
import { attemptAsync, isOk } from 'massaman/control'
const result = await attemptAsync(() => fetch('/api/user').then((r) => r.json()))
if (isOk(result)) {
console.log(result.value)
} else {
console.error(result.error.message)
}
```
## Why?
Two Rust patterns I keep wanting in TypeScript: `match` for exhaustive branching, and `Result` for errors that compose without throws.
In Rust:
```rust
match action {
Action::Load => "loading",
Action::Success => "done",
Action::Error(msg) => &format!("failed: {}", msg),
}
let parsed: Result = serde_json::from_str(raw);
match parsed {
Ok(user) => println!("got: {}", user.name),
Err(err) => eprintln!("failed: {}", err),
}
```
The equivalent in TypeScript using `massaman`:
```ts
import { match, P } from 'massaman/pattern'
import { attempt, isOk } from 'massaman/control'
match(action)
.with({ type: 'load' }, () => 'loading')
.with({ type: 'success' }, () => 'done')
.with({ type: 'error', msg: P.string }, ({ msg }) => `failed: ${msg}`)
.exhaustive()
const parsed = attempt(() => JSON.parse(raw) as User)
if (isOk(parsed)) {
console.log(`got: ${parsed.value.name}`)
} else {
console.error(`failed: ${parsed.error.message}`)
}
```
`massaman` brings both patterns to TypeScript, layered over [es-toolkit](https://es-toolkit.dev) and [ts-pattern](https://github.com/gvergnaud/ts-pattern), plus a thin set of utilities filling the gaps: async-aware composition, variadic-narrowing predicates, and consistent error normalization.
More on the philosophy at [zrosenbauer.com/gui/blog](https://zrosenbauer.com/gui/blog).
## Contributing
See [CONTRIBUTING.md](https://github.com/zrosenbauer/massaman/blob/main/CONTRIBUTING.md) for development setup, conventions, and PR process.
## License
[MIT](LICENSE)