Open source TypeScript toolkit

Type-safe errors, DI, and Result in plain async/await

The patterns you'd build from Effect and Rust — typed errors, dependency injection, Result types, retries, and more — in TypeScript you already know.

Get Started

For teams using TypeScript in production who want Effect-level patterns without the learning curve.

import { Define, Result } from "within-ts"class NotFound extends Define.Error("NotFound")<{ id: string }>() {}class Db extends Define.Service("Db")<typeof postgres>() {  static default() { return postgres }}class UserRepo extends Define.Entity<User>() {  static async getById(id: string) {    const user = await new Db().select(users).where(eq(users.id, id)).first()    if (!user) return Result.err(new NotFound({ id }))    return Result.ok(new UserRepo(user))  }}async function getUser(id: string) {  return UserRepo.getById(id)}

See the transformation

Four small changes. Completely different code.

Watch the same function evolve from a fragile try/catch to typed, testable, injectable code — one step at a time.

A typical TypeScript function

This is what most codebases look like. The function works — until it doesn't.

app.ts
1 async function getUser(id: string) {
2 const user = await db.select(users).where(eq(users.id, id)).first()
3 if (!user) throw new Error("not found")
4 return user
5 }

Testing

Swap any dependency in one line

Services use AsyncLocalStorage under the hood. Call Db.run(testDb, fn) to override any service for the duration of a callback — no mocking libraries, no DI frameworks.

it("returns NotFound for missing users", async () => {  const result = await Db.run(testDb, () =>    UserRepo.getById("nonexistent")  )  expect(result.ok).toBe(false)  expect(result.error._tag).toBe("NotFound")})

Start building better TypeScript

Pick the problem you're solving today. Each module stands alone — adopt one, adopt all, no lock-in.