© 2026 Hedgehog Software, LLC
interface ProductsRepositoryImpl { readonly count: () => Effect.Effect<number, DatabaseError>; readonly getAll: () => Effect.Effect<Array<Product>, DatabaseError>; } export class ProductsRepository extends Context.Tag("ProductsRepository")< ProductsRepository, ProductsRepositoryImpl >() {} export class ProductsRepositoryLive extends ProductsRepository { constructor() { super(undefined as never); // Hackery for TS to pass } getAll() { return Effect.tryPromise({ try: () => db.products.toArray(), catch: (error) => new DatabaseError({ message: `Failed to get all products: ${error}` }), }); } count() { return Effect.tryPromise({ try: () => db.products.count(), catch: (error) => new DatabaseError({ message: `Failed to get products count, ${error}`, }), }); } }
const runnable = ProductsRepository.pipe( Effect.flatMap((repo) => repo.count()), Effect.provideService(ProductsRepository, new ProductsRepositoryLive()), );
ProductsRepositoryLive
constructor() { super(undefined as never); }
InMemoryProductsRepository
export class ProductsRepositoryInMemory extends ProductsRepository { private products = [product1, product2]; constructor() { super(undefined as never); } getAll() { return Effect.try({ try: () => this.products, catch: (error) => new DatabaseError({ message: `Failed to get all products: ${error}` }), }); } // etc.... }