The Context module provides a data structure for dependency injection in effectful programs. It’s a type-safe table mapping Tags to their service implementations.
Types
Context
interface Context<in Services>
A context is a collection of services indexed by tags.
The union of service identifiers available in this context
Tag
interface Tag<in out Id, in out Value>
A tag identifies a service in the context.
The unique identifier for this service
The service implementation type
Constructors
empty
Returns an empty Context.
const empty: () => Context<never>
An empty context with no services
import { Context } from "effect"
const ctx = Context.empty()
make
Creates a new Context with a single service.
const make: <I, S>(tag: Tag<I, S>, service: S) => Context<I>
The service implementation
A context containing the single service
import { Context } from "effect"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const ctx = Context.make(Port, { PORT: 8080 })
GenericTag
Creates a new Tag with an optional key parameter.
const GenericTag: <Identifier, Service = Identifier>(key: string) => Tag<Identifier, Service>
The unique key for this tag
import { Context } from "effect"
const Database = Context.GenericTag<{ query: (sql: string) => string }>("Database")
Tag
Creates a tag class for defining services.
const Tag: <const Id extends string>(id: Id) => <Self, Shape>() => TagClass<Self, Id, Shape>
The unique identifier for the tag
A tag class that can be extended
import { Context } from "effect"
class MyService extends Context.Tag("MyService")<
MyService,
{ readonly value: number }
>() {}
Reference
Creates a context tag with a default value.
const Reference: <Self>() => <const Id extends string, Service>(
id: Id,
options: { readonly defaultValue: () => Service }
) => ReferenceClass<Self, Id, Service>
Function providing the default value
A reference that provides a default value
import { Context, Effect } from "effect"
class SpecialNumber extends Context.Reference<SpecialNumber>()(
"SpecialNumber",
{ defaultValue: () => 2048 }
) {}
const program = Effect.gen(function* () {
const num = yield* SpecialNumber
console.log(num) // 2048
})
References are useful for optional services that have sensible defaults.
Operations
add
Adds a service to a context.
const add: {
<I, S>(tag: Tag<I, S>, service: S): <Services>(self: Context<Services>) => Context<Services | I>
<Services, I, S>(self: Context<Services>, tag: Tag<I, S>, service: S): Context<Services | I>
}
self
Context<Services>
required
The existing context
The service implementation
A new context with the added service
import { Context, pipe } from "effect"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Timeout = Context.GenericTag<{ TIMEOUT: number }>("Timeout")
const ctx = pipe(
Context.make(Port, { PORT: 8080 }),
Context.add(Timeout, { TIMEOUT: 5000 })
)
get
Retrieves a service from the context.
const get: {
<I, S>(tag: Reference<I, S>): <Services>(self: Context<Services>) => S
<Services, I extends Services, S>(tag: Tag<I, S>): (self: Context<Services>) => S
<Services, I, S>(self: Context<Services>, tag: Reference<I, S>): S
<Services, I extends Services, S>(self: Context<Services>, tag: Tag<I, S>): S
}
self
Context<Services>
required
The context to get from
The tag identifying the service
The service implementation
import { Context } from "effect"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const ctx = Context.make(Port, { PORT: 8080 })
const port = Context.get(ctx, Port)
// { PORT: 8080 }
getOption
Retrieves a service wrapped in an Option.
const getOption: {
<S, I>(tag: Tag<I, S>): <Services>(self: Context<Services>) => Option<S>
<Services, S, I>(self: Context<Services>, tag: Tag<I, S>): Option<S>
}
self
Context<Services>
required
The context to get from
The tag identifying the service
Some(service) if present, None otherwise
import { Context, Option } from "effect"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const ctx = Context.empty()
const maybePort = Context.getOption(ctx, Port)
// Option.none()
merge
Merges two contexts.
const merge: {
<R1>(that: Context<R1>): <Services>(self: Context<Services>) => Context<R1 | Services>
<Services, R1>(self: Context<Services>, that: Context<R1>): Context<Services | R1>
}
self
Context<Services>
required
The first context
A context containing services from both
import { Context } from "effect"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Timeout = Context.GenericTag<{ TIMEOUT: number }>("Timeout")
const ctx1 = Context.make(Port, { PORT: 8080 })
const ctx2 = Context.make(Timeout, { TIMEOUT: 5000 })
const merged = Context.merge(ctx1, ctx2)
pick
Returns a new Context containing only specified services.
const pick: <Tags extends ReadonlyArray<Tag<any, any>>>(
...tags: Tags
) => <Services>(self: Context<Services>) => Context<Services & Tag.Identifier<Tags[number]>>
self
Context<Services>
required
The source context
A context with only the picked services
import { Context, pipe } from "effect"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Timeout = Context.GenericTag<{ TIMEOUT: number }>("Timeout")
const ctx = pipe(
Context.make(Port, { PORT: 8080 }),
Context.add(Timeout, { TIMEOUT: 5000 })
)
const onlyPort = pipe(ctx, Context.pick(Port))
omit
Returns a new Context excluding specified services.
const omit: <Tags extends ReadonlyArray<Tag<any, any>>>(
...tags: Tags
) => <Services>(self: Context<Services>) => Context<Exclude<Services, Tag.Identifier<Tags[number]>>>
Guards
isContext
Checks if a value is a Context.
const isContext: (input: unknown) => input is Context<never>
true if the value is a Context
import { Context } from "effect"
Context.isContext(Context.empty()) // true
Context.isContext({}) // false
isTag
Checks if a value is a Tag.
const isTag: (input: unknown) => input is Tag<any, any>
isReference
Checks if a value is a Reference.
const isReference: (u: unknown) => u is Reference<any, any>