Context.mergeAll

In Context.merge (24) we saw how to combine two contexts. Context.mergeAll is similar, but it allows passing an arbitrary number of contexts in as the argument.

import { Context } from "effect";
class One extends Context.Tag("One")<One, 1>() {}
class Two extends Context.Tag("Two")<Two, 2>() {}
class Three extends Context.Tag("Three")<Three, 3>() {}
// ┌─── Context.Context<One | Two | Three>
// ▼
const merged = Context.mergeAll(
Context.make(One, 1),
Context.make(Two, 2),
Context.make(Three, 3)
);

We can implement mergeAll using Context.merge (24) and Context.empty (22) . The type signature makes this appear much more complex than it is. This is a common functional programming technique building on mathematical induction. If we know how to combine two items, and we know how to construct a “base”/“empty” item, then we can combine an array of items recursively.

const mergeAll = <T extends Array<unknown>>(
...ctxs: [...{ [K in keyof T]: Context.Context<T[K]> }]
): Context.Context<T[number]> =>
ctxs.reduce(Context.merge, Context.empty() as Context.Context<T[number]>);

Let’s recap:

  • Context.mergeAll combines many Contexts
  • It returns a new, larger Context
  • It does not mutate the Contexts passed in