interface / @typed/fx/Fx

Fx

Fx is a reactive stream of values that supports concurrency, error handling, and context management, fully integrated with the Effect ecosystem.

Conceptually, an Fx<A, E, R> is a push-based stream that:

  • Emits values of type A
  • Can fail with an error of type E
  • Requires a context/environment of type R

Unlike a standard Effect which produces a single value, Fx can produce 0, 1, or many values over time. It is similar to RxJS Observables or AsyncIterables, but built on top of Effect’s fiber-based concurrency model.

Package version
2.0.0-beta.13
Category
Type contracts
Since
1.0.0

Import

import { Fx } from "@typed/fx/Fx";

Signatures

export interface Fx<A, E = never, R = never> extends Pipeable {
    readonly [FxTypeId]: Fx.Variance<A, E, R>;
    readonly run: <RSink>(sink: Sink.Sink<A, E, RSink>) => Effect.Effect<unknown, never, R | RSink>;
}
export declare namespace Fx {
    type Any = Fx<any, any, any>;
    interface Variance<A, E, R> {
        readonly _A: Types.Covariant<A>;
        readonly _E: Types.Covariant<E>;
        readonly _R: Types.Covariant<R>;
    }
    type Success<T> = [
        T
    ] extends [
        never
    ] ? never : T extends Fx<infer _A, infer _E, infer _R> ? _A : never;
    type Error<T> = [
        T
    ] extends [
        never
    ] ? never : T extends Fx<infer _A, infer _E, infer _R> ? _E : never;
    type Services<T> = [
        T
    ] extends [
        never
    ] ? never : [
        T
    ] extends [
        Fx<infer _A, infer _E, infer _R>
    ] ? _R : never;
    interface Service<Self, Id extends string, A, E> extends Fx<A, E, Self> {
        readonly id: Id;
        readonly service: Context.Service<Self, Fx<A, E>>;
        readonly make: <R = never>(fx: Fx<A, E, R> | Effect.Effect<Fx<A, E, R>, E, R>) => Layer<Self, E, Exclude<R, Scope.Scope>>;
    }
    interface Class<Self, Id extends string, A, E> extends Service<Self, Id, A, E> {
        new (): Service<Self, Id, A, E>;
    }
}

Why

Browser events, clocks, sockets, and users decide when work exists. Fx models that producer-driven direction while retaining Effect’s explicit success, error, and service channels. An Effect, Stream, Promise, ReadableStream, iterable, or custom source can participate through an explicit constructor; Fx extends the Effect ecosystem rather than replacing it.

Ownership and lifetime

Constructing an Fx starts no work. Calling run returns an Effect whose running fiber and Scope own subscriptions, child fibers, and finalizers. Interruption propagates through that Effect lifetime. The supplied Sink contributes its requirements to run; failures are delivered to the Sink, which is why the returned Effect itself cannot fail.

Composition

The type parameters follow Effect’s A, E, R vocabulary. Consequently, an Fx<RenderEvent, E, R> can describe arbitrary UI without hiding its failures or required services.

Effect foundations

Fx execution is an Effect, resource ownership uses Scope, concurrent runs use Fiber, and failures retain Effect’s structured Cause.

Property: [[computed:[FxTypeId]]]

Identifies this value as an Fx and records its success, error, and service variance.

Property: [[computed:[FxTypeId]]]: Why

The marker makes Fx distinguishable at runtime without executing it, while its type carries the three channels through structural composition.

Property: [[computed:[FxTypeId]]]: Ownership and lifetime

Reading the marker starts no work and acquires no resources.

Property: run

Connects this producer to a Sink and returns the Effect that owns the connection.

Property: run: Why

Keeping execution behind an Effect preserves typed services, structured concurrency, and interruption instead of starting hidden work during construction. Values are offered to the sink in the order chosen by this Fx; the producer may emit zero, one, or many values.

Property: run: Ownership and lifetime

Work starts when the returned Effect runs. Its fiber owns the subscription and any child scopes. Interrupting it interrupts the producer and runs its finalizers. Producer failures are delivered to sink.onFailure, so they are not repeated in the returned Effect’s error channel.

Examples

import { Effect } from "effect"
import { Fx } from "@typed/fx"

const keys: Fx.Fx<KeyboardEvent> = Fx.callback((emit) => {
  const onKey = (event: KeyboardEvent) => emit.succeed(event)
  document.addEventListener("keydown", onKey)
  return Effect.sync(() => document.removeEventListener("keydown", onKey))
})

Members

  • Fx.Any

    Matches any Fx regardless of its value, error, or service channels.

  • Fx.Class

    The constructible service class returned by Fx.Service.

  • Fx.Error

    Extracts the typed error from an Fx.

  • Fx.Service

    An Fx whose implementation is obtained from an Effect service.

  • Fx.Services

    Extracts the services required to run an Fx.

  • Fx.Success

    Extracts the emitted value type from an Fx.

  • Fx.Variance

    Describes how an Fx varies in its value, error, and service channels.

Other public imports

These import paths expose the same declaration. Each page retains its own public name and signature.

Related reading

Source