Context overview
This module provides a data structure called Context
that can be used for dependency injection in effectful programs. It is essentially a table mapping Tag
s to their implementations (called Service
s), and can be used to manage dependencies in a type-safe way. The Context
data structure is essentially a way of providing access to a set of related services that can be passed around as a single unit. This module provides functions to create, modify, and query the contents of a Context
, as well as a number of utility types for working with tags and services.
Added in v2.0.0
Table of contents
constructors
GenericTag
Creates a new Tag
instance with an optional key parameter.
Signature
export declare const GenericTag: <Identifier, Service = Identifier>(key: string) => Tag<Identifier, Service>
Example
import * as Context from "effect/Context"
assert.strictEqual(Context.GenericTag("PORT").key === Context.GenericTag("PORT").key, true)
Added in v2.0.0
Tag
Signature
export declare const Tag: <const Id extends string>(id: Id) => <Self, Shape>() => TagClass<Self, Id, Shape>
Added in v2.0.0
empty
Returns an empty Context
.
Signature
export declare const empty: () => Context<never>
Example
import * as Context from "effect/Context"
assert.strictEqual(Context.isContext(Context.empty()), true)
Added in v2.0.0
make
Creates a new Context
with a single service associated to the tag.
Signature
export declare const make: <T extends Tag<any, any>>(tag: T, service: Tag.Service<T>) => Context<Tag.Identifier<T>>
Example
import * as Context from "effect/Context"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Services = Context.make(Port, { PORT: 8080 })
assert.deepStrictEqual(Context.get(Services, Port), { PORT: 8080 })
Added in v2.0.0
unsafeMake
Signature
export declare const unsafeMake: <Services>(unsafeMap: Map<string, any>) => Context<Services>
Added in v2.0.0
getters
get
Get a service from the context that corresponds to the given tag.
Signature
export declare const get: {
<Services, T extends ValidTagsById<Services>>(tag: T): (self: Context<Services>) => Tag.Service<T>
<Services, T extends ValidTagsById<Services>>(self: Context<Services>, tag: T): Tag.Service<T>
}
Example
import * as Context from "effect/Context"
import { pipe } from "effect/Function"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Timeout = Context.GenericTag<{ TIMEOUT: number }>("Timeout")
const Services = pipe(Context.make(Port, { PORT: 8080 }), Context.add(Timeout, { TIMEOUT: 5000 }))
assert.deepStrictEqual(Context.get(Services, Timeout), { TIMEOUT: 5000 })
Added in v2.0.0
getOption
Get the value associated with the specified tag from the context wrapped in an Option
object. If the tag is not found, the Option
object will be None
.
Signature
export declare 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>
}
Example
import * as Context from "effect/Context"
import * as O from "effect/Option"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Timeout = Context.GenericTag<{ TIMEOUT: number }>("Timeout")
const Services = Context.make(Port, { PORT: 8080 })
assert.deepStrictEqual(Context.getOption(Services, Port), O.some({ PORT: 8080 }))
assert.deepStrictEqual(Context.getOption(Services, Timeout), O.none())
Added in v2.0.0
guards
isContext
Checks if the provided argument is a Context
.
Signature
export declare const isContext: (input: unknown) => input is Context<never>
Example
import * as Context from "effect/Context"
assert.strictEqual(Context.isContext(Context.empty()), true)
Added in v2.0.0
isTag
Checks if the provided argument is a Tag
.
Signature
export declare const isTag: (input: unknown) => input is Tag<any, any>
Example
import * as Context from "effect/Context"
assert.strictEqual(Context.isTag(Context.GenericTag("Tag")), true)
Added in v2.0.0
models
Context (interface)
Signature
export interface Context<in Services> extends Equal, Pipeable, Inspectable {
readonly [TypeId]: {
readonly _Services: Types.Contravariant<Services>
}
readonly unsafeMap: Map<string, any>
}
Added in v2.0.0
Tag (interface)
Signature
export interface Tag<in out Id, in out Value> extends Pipeable, Inspectable {
readonly _tag: "Tag"
readonly _op: "Tag"
readonly [TagTypeId]: {
readonly _Service: Types.Invariant<Value>
readonly _Identifier: Types.Invariant<Id>
}
of(self: Value): Value
context(self: Value): Context<Id>
readonly stack?: string | undefined
readonly key: string
[Unify.typeSymbol]?: unknown
[Unify.unifySymbol]?: TagUnify<this>
[Unify.ignoreSymbol]?: TagUnifyIgnore
}
Added in v2.0.0
TagClass (interface)
Signature
export interface TagClass<Self, Id, Type> extends Tag<Self, Type> {
new (_: never): TagClassShape<Id, Type>
}
Added in v2.0.0
TagClassShape (interface)
Signature
export interface TagClassShape<Id, Shape> {
readonly [TagTypeId]: TagTypeId
readonly Type: Shape
readonly Id: Id
}
Added in v2.0.0
TagUnify (interface)
Signature
export interface TagUnify<A extends { [Unify.typeSymbol]?: any }> {
Tag?: () => A[Unify.typeSymbol] extends Tag<infer I0, infer S0> | infer _ ? Tag<I0, S0> : never
}
Added in v2.0.0
TagUnifyIgnore (interface)
Signature
export interface TagUnifyIgnore {}
Added in v2.0.0
ValidTagsById (type alias)
Signature
export type ValidTagsById<R> = R extends infer S ? Tag<S, any> : never
Added in v2.0.0
symbol
TagTypeId (type alias)
Signature
export type TagTypeId = typeof TagTypeId
Added in v2.0.0
TypeId (type alias)
Signature
export type TypeId = typeof TypeId
Added in v2.0.0
unsafe
unsafeGet
Get a service from the context that corresponds to the given tag. This function is unsafe because if the tag is not present in the context, a runtime error will be thrown.
For a safer version see {@link getOption}.
Signature
export declare const unsafeGet: {
<S, I>(tag: Tag<I, S>): <Services>(self: Context<Services>) => S
<Services, S, I>(self: Context<Services>, tag: Tag<I, S>): S
}
Example
import * as Context from "effect/Context"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Timeout = Context.GenericTag<{ TIMEOUT: number }>("Timeout")
const Services = Context.make(Port, { PORT: 8080 })
assert.deepStrictEqual(Context.unsafeGet(Services, Port), { PORT: 8080 })
assert.throws(() => Context.unsafeGet(Services, Timeout))
Added in v2.0.0
utils
Tag (namespace)
Added in v2.0.0
Identifier (type alias)
Signature
export type Identifier<T extends Tag<any, any> | TagClassShape<any, any>> =
T extends Tag<infer A, any> ? A : T extends TagClassShape<infer A, any> ? A : never
Added in v2.0.0
Service (type alias)
Signature
export type Service<T extends Tag<any, any> | TagClassShape<any, any>> =
T extends Tag<any, infer A> ? A : T extends TagClassShape<any, infer A> ? A : never
Added in v2.0.0
add
Adds a service to a given Context
.
Signature
export declare const add: {
<T extends Tag<any, any>>(
tag: T,
service: Tag.Service<T>
): <Services>(self: Context<Services>) => Context<Services | Tag.Identifier<T>>
<Services, T extends Tag<any, any>>(
self: Context<Services>,
tag: T,
service: Tag.Service<T>
): Context<Services | Tag.Identifier<T>>
}
Example
import * as Context from "effect/Context"
import { pipe } from "effect/Function"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Timeout = Context.GenericTag<{ TIMEOUT: number }>("Timeout")
const someContext = Context.make(Port, { PORT: 8080 })
const Services = pipe(someContext, Context.add(Timeout, { TIMEOUT: 5000 }))
assert.deepStrictEqual(Context.get(Services, Port), { PORT: 8080 })
assert.deepStrictEqual(Context.get(Services, Timeout), { TIMEOUT: 5000 })
Added in v2.0.0
merge
Merges two Context
s, returning a new Context
containing the services of both.
Signature
export declare const merge: {
<R1>(that: Context<R1>): <Services>(self: Context<Services>) => Context<R1 | Services>
<Services, R1>(self: Context<Services>, that: Context<R1>): Context<Services | R1>
}
Example
import * as Context from "effect/Context"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Timeout = Context.GenericTag<{ TIMEOUT: number }>("Timeout")
const firstContext = Context.make(Port, { PORT: 8080 })
const secondContext = Context.make(Timeout, { TIMEOUT: 5000 })
const Services = Context.merge(firstContext, secondContext)
assert.deepStrictEqual(Context.get(Services, Port), { PORT: 8080 })
assert.deepStrictEqual(Context.get(Services, Timeout), { TIMEOUT: 5000 })
Added in v2.0.0
omit
Signature
export declare const omit: <Services, S extends ValidTagsById<Services>[]>(
...tags: S
) => (self: Context<Services>) => Context<Exclude<Services, { [k in keyof S]: Tag.Identifier<S[k]> }[keyof S]>>
Added in v2.0.0
pick
Returns a new Context
that contains only the specified services.
Signature
export declare const pick: <Services, S extends ValidTagsById<Services>[]>(
...tags: S
) => (self: Context<Services>) => Context<{ [k in keyof S]: Tag.Identifier<S[k]> }[number]>
Example
import * as Context from "effect/Context"
import { pipe } from "effect/Function"
import * as O from "effect/Option"
const Port = Context.GenericTag<{ PORT: number }>("Port")
const Timeout = Context.GenericTag<{ TIMEOUT: number }>("Timeout")
const someContext = pipe(Context.make(Port, { PORT: 8080 }), Context.add(Timeout, { TIMEOUT: 5000 }))
const Services = pipe(someContext, Context.pick(Port))
assert.deepStrictEqual(Context.getOption(Services, Port), O.some({ PORT: 8080 }))
assert.deepStrictEqual(Context.getOption(Services, Timeout), O.none())
Added in v2.0.0