Type-safe by default
Every function, every monad, every composition is fully typed. TypeScript inference works end-to-end with no casts needed.
Type-safe by default
Every function, every monad, every composition is fully typed. TypeScript inference works end-to-end with no casts needed.
Real-world patterns
Built for production applications. ReaderTaskEither provides dependency injection, async operations, and error handling in a single type.
Zero dependencies
No runtime dependencies. Tree-shakeable modular imports keep your bundle small.
Composable
Everything composes with pipe and flow. Build complex workflows from simple, reusable functions.
import * as RTE from "@oofp/core/reader-task-either";import * as E from "@oofp/core/either";import { pipe } from "@oofp/core/pipe";
interface AppContext { db: Database; logger: Logger;}
const findUser = (id: string) => pipe( RTE.ask<AppContext>(), RTE.chaint((ctx) => ctx.db.findUser(id)), RTE.tapRTE((user) => logAccess(user)), );
// Execute at the boundaryconst result = await RTE.run(appContext)(findUser("123"))();
pipe( result, E.fold( (error) => console.error(error), (user) => console.log(user), ),);