CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-effect

The missing standard library for TypeScript, for writing production-grade software.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

effect-core.mddocs/

Core Effect System

The heart of the Effect library - defines the fundamental Effect<A, E, R> type and core operations for creating, transforming, and executing effects with structured error handling and context management.

Capabilities

Effect Type

The core Effect<A, E, R> type represents computations that may succeed with value A, fail with error E, and require context R.

/**
 * The Effect type represents a computation that may succeed with a value of type A,
 * fail with an error of type E, or require a context of type R
 */
interface Effect<out A, out E = never, out R = never> extends Pipeable {
  readonly [EffectTypeId]: Effect.Variance<A, E, R>;
}

interface Variance<out A, out E, out R> {
  readonly _A: Covariant<A>;
  readonly _E: Covariant<E>;
  readonly _R: Covariant<R>;
}

Effect Creation

Functions for creating new Effect instances from values, errors, synchronous computations, and asynchronous operations.

/**
 * Creates an Effect that succeeds with the provided value
 */
function succeed<A>(value: A): Effect<A>;

/**
 * Creates an Effect that fails with the provided error
 */
function fail<E>(error: E): Effect<never, E>;

/**
 * Creates an Effect from a synchronous side-effecting function
 */
function sync<A>(thunk: LazyArg<A>): Effect<A>;

/**
 * Creates an Effect from an asynchronous operation using a callback
 */
function async<A, E = never, R = never>(
  register: (callback: (effect: Effect<A, E, R>) => void) => void
): Effect<A, E, R>;

/**
 * Creates an Effect that never completes
 */
function never: Effect<never>;

/**
 * Creates an Effect that succeeds with void
 */
function void: Effect<void>;

/**
 * Creates an Effect from a Promise
 */
function promise<A>(evaluate: LazyArg<Promise<A>>): Effect<A, never>;

/**
 * Creates an Effect from a Promise that may reject
 */
function tryPromise<A, E>(options: {
  readonly try: LazyArg<Promise<A>>;
  readonly catch: (unknown: unknown) => E;
}): Effect<A, E>;

Usage Examples:

import { Effect } from "effect";

// Success values
const successEffect = Effect.succeed(42);
const stringEffect = Effect.succeed("Hello World");

// Failures
const failureEffect = Effect.fail("Something went wrong");
const errorEffect = Effect.fail(new Error("Network error"));

// Synchronous effects
const syncEffect = Effect.sync(() => {
  console.log("Side effect!");
  return Math.random();
});

// Asynchronous effects
const asyncEffect = Effect.async<string, Error>((callback) => {
  setTimeout(() => {
    callback(Effect.succeed("Delayed result"));
  }, 1000);
});

// From promises
const promiseEffect = Effect.promise(() => fetch("/api/data"));
const safePromiseEffect = Effect.tryPromise({
  try: () => fetch("/api/data"),
  catch: (unknown) => `Network error: ${unknown}`
});

Effect Transformations

Functions for transforming Effect values while preserving error and context information.

/**
 * Transforms the success value of an Effect
 */
function map<A, B>(f: (a: A) => B): <E, R>(self: Effect<A, E, R>) => Effect<B, E, R>;

/**
 * Chains effects together, allowing the success value to determine the next effect
 */
function flatMap<A, B, E2, R2>(
  f: (a: A) => Effect<B, E2, R2>
): <E1, R1>(self: Effect<A, E1, R1>) => Effect<B, E1 | E2, R1 | R2>;

/**
 * Performs a side effect without changing the result
 */
function tap<A, X, E2, R2>(
  f: (a: A) => Effect<X, E2, R2>
): <E1, R1>(self: Effect<A, E1, R1>) => Effect<A, E1 | E2, R1 | R2>;

/**
 * Transforms both success and error values
 */
function mapBoth<E, E2, A, A2>(options: {
  readonly onFailure: (e: E) => E2;
  readonly onSuccess: (a: A) => A2;
}): <R>(self: Effect<A, E, R>) => Effect<A2, E2, R>;

/**
 * Transforms the error value of an Effect
 */
function mapError<E, E2>(f: (e: E) => E2): <A, R>(self: Effect<A, E, R>) => Effect<A, E2, R>;

/**
 * Flattens nested Effects
 */
function flatten<A, E1, R1, E2, R2>(
  self: Effect<Effect<A, E2, R2>, E1, R1>
): Effect<A, E1 | E2, R1 | R2>;

Usage Examples:

import { Effect, pipe } from "effect";

// Basic transformations
const doubled = pipe(
  Effect.succeed(21),
  Effect.map(x => x * 2)
); // Effect<number, never, never>

// Chaining effects
const program = pipe(
  Effect.succeed("input"),
  Effect.flatMap(input => 
    Effect.sync(() => input.toUpperCase())
  ),
  Effect.tap(result => 
    Effect.sync(() => console.log(`Result: ${result}`))
  )
); // Effect<string, never, never>

// Error transformation
const betterError = pipe(
  Effect.fail("generic error"),
  Effect.mapError(err => new Error(`Enhanced: ${err}`))
); // Effect<never, Error, never>

Error Handling

Comprehensive error handling capabilities for recovering from failures and managing error flow.

/**
 * Handles all errors by providing a recovery effect
 */
function catchAll<E, A2, E2, R2>(
  f: (e: E) => Effect<A2, E2, R2>
): <A, R>(self: Effect<A, E, R>) => Effect<A | A2, E2, R | R2>;

/**
 * Handles specific errors using a tag-based approach
 */
function catchTag<K extends E extends { _tag: string } ? E["_tag"] : never, E, A1, E1, R1>(
  k: K,
  f: (e: Extract<E, { _tag: K }>) => Effect<A1, E1, R1>
): <A, R>(self: Effect<A, E, R>) => Effect<A | A1, E1 | Exclude<E, { _tag: K }>, R | R1>;

/**
 * Handles some errors while preserving others
 */
function catchSome<E, A2, E2, R2>(
  pf: (e: E) => Option<Effect<A2, E2, R2>>
): <A, R>(self: Effect<A, E, R>) => Effect<A | A2, E | E2, R | R2>;

/**
 * Provides a fallback effect if the original fails
 */
function orElse<A2, E2, R2>(
  that: LazyArg<Effect<A2, E2, R2>>
): <A, E, R>(self: Effect<A, E, R>) => Effect<A | A2, E2, R | R2>;

/**
 * Handles defects (unexpected errors) that would normally crash the program
 */
function catchAllDefect<A2, E2, R2>(
  f: (defect: unknown) => Effect<A2, E2, R2>
): <A, E, R>(self: Effect<A, E, R>) => Effect<A | A2, E | E2, R | R2>;

/**
 * Ensures an effect runs regardless of success or failure
 */
function ensuring<X, E2, R2>(
  finalizer: Effect<X, E2, R2>
): <A, E, R>(self: Effect<A, E, R>) => Effect<A, E | E2, R | R2>;

/**
 * Retries an effect according to a schedule
 */
function retry<S, R1, O>(
  policy: Schedule<S, any, O>
): <A, E, R>(self: Effect<A, E, R>) => Effect<A, E, R | R1>;

Usage Examples:

import { Effect, pipe } from "effect";

// Basic error recovery
const recovered = pipe(
  Effect.fail("Network timeout"),
  Effect.catchAll(error => Effect.succeed(`Fallback for: ${error}`))
);

// Selective error handling
const selective = pipe(
  riskyOperation,
  Effect.catchTag("NetworkError", error => 
    Effect.succeed(`Retrying after network error: ${error.message}`)
  ),
  Effect.catchTag("ValidationError", error =>
    Effect.fail(`Invalid input: ${error.field}`)
  )
);

// Fallback chain
const withFallback = pipe(
  primaryService,
  Effect.orElse(() => backupService),
  Effect.orElse(() => Effect.succeed("default value"))
);

// Cleanup guarantee
const safeOperation = pipe(
  acquireResource,
  Effect.flatMap(resource => doWork(resource)),
  Effect.ensuring(releaseResource)
);

Effect Execution

Functions for running Effect computations and extracting their results.

/**
 * Runs an Effect and returns a Promise of the result
 */
function runPromise<A, E>(effect: Effect<A, E>): Promise<A>;

/**
 * Runs an Effect synchronously and returns the result
 * Throws if the effect is asynchronous or fails
 */
function runSync<A, E>(effect: Effect<A, E>): A;

/**
 * Runs an Effect and returns an Exit value representing success or failure
 */
function runPromiseExit<A, E>(effect: Effect<A, E>): Promise<Exit<A, E>>;

/**
 * Runs an Effect synchronously and returns an Exit value
 */
function runSyncExit<A, E>(effect: Effect<A, E>): Exit<A, E>;

/**
 * Runs an Effect with a callback for the result
 */
function runCallback<A, E>(
  effect: Effect<A, E>
): (callback?: (exit: Exit<A, E>) => void) => (fiberId?: FiberId) => void;

Usage Examples:

import { Effect } from "effect";

// Promise-based execution
const result = await Effect.runPromise(
  Effect.succeed(42)
); // 42

// Synchronous execution
const syncResult = Effect.runSync(
  Effect.succeed("Hello")
); // "Hello"

// Safe execution with Exit
const exit = await Effect.runPromiseExit(
  Effect.fail("Something went wrong")
);
if (exit._tag === "Success") {
  console.log(exit.value);
} else {
  console.error(exit.cause);
}

// Error handling in promises
try {
  await Effect.runPromise(Effect.fail("Error"));
} catch (error) {
  console.error("Effect failed:", error);
}

Context Operations

Functions for working with Effect context requirements for dependency injection.

/**
 * Access a service from the context
 */
function service<T>(tag: Tag<T, T>): Effect<T, never, T>;

/**
 * Provide a service to an Effect
 */
function provideService<T>(tag: Tag<T, T>, service: T): <A, E, R>(self: Effect<A, E, R>) => Effect<A, E, Exclude<R, T>>;

/**
 * Provide a complete context to an Effect
 */
function provideContext<R>(context: Context<R>): <A, E>(self: Effect<A, E, R>) => Effect<A, E>;

/**
 * Access the entire context
 */
function context<R>(): Effect<Context<R>, never, R>;

/**
 * Provide context using an Effect
 */
function provideServiceEffect<T, E, R>(
  tag: Tag<T, T>,
  effect: Effect<T, E, R>
): <A, E1, R1>(self: Effect<A, E1, R1 | T>) => Effect<A, E | E1, R | Exclude<R1, T>>;

Usage Examples:

import { Effect, Context } from "effect";

// Define a service
interface Logger {
  log(message: string): Effect<void>;
}
const Logger = Context.GenericTag<Logger>("Logger");

// Use the service
const program = Effect.gen(function* () {
  const logger = yield* Logger;
  yield* logger.log("Hello from program");
  return "done";
});

// Provide the service
const logger: Logger = {
  log: (message) => Effect.sync(() => console.log(message))
};

const runnable = pipe(
  program,
  Effect.provideService(Logger, logger)
);

await Effect.runPromise(runnable);

Generator Syntax

Effect provides generator-based syntax for writing imperative-style code with effects.

/**
 * Creates an Effect from a generator function
 */
function gen<Eff extends YieldWrap<Effect<any, any, any>>, AEff>(
  f: (resume: Adapter) => Generator<Eff, AEff, any>
): Effect<AEff, Effect.Error<Eff>, Effect.Context<Eff>>;

/**
 * Do notation for Effect computations
 */
const Do: Effect<{}>;

/**
 * Bind a value in Do notation
 */
function bind<N extends string, A, E2, R2>(
  name: Exclude<N, keyof A>,
  f: (a: A) => Effect<N, E2, R2>
): <E1, R1>(self: Effect<A, E1, R1>) => Effect<A & { [K in N]: N }, E1 | E2, R1 | R2>;

Usage Examples:

import { Effect } from "effect";

// Generator syntax
const program = Effect.gen(function* () {
  const x = yield* Effect.succeed(10);
  const y = yield* Effect.succeed(20);
  const sum = x + y;
  yield* Effect.sync(() => console.log(`Sum: ${sum}`));
  return sum;
});

// Do notation
const doProgram = pipe(
  Effect.Do,
  Effect.bind("x", () => Effect.succeed(10)),
  Effect.bind("y", () => Effect.succeed(20)),
  Effect.bind("sum", ({ x, y }) => Effect.succeed(x + y)),
  Effect.tap(({ sum }) => Effect.sync(() => console.log(`Sum: ${sum}`))),
  Effect.map(({ sum }) => sum)
);

Types

// Lazy evaluation type
type LazyArg<A> = () => A;

// Effect variance markers
interface Covariant<T> {
  readonly _T: (_: never) => T;
}

interface Contravariant<T> {
  readonly _T: (_: T) => void;
}

// Exit type for effect results
type Exit<A, E = never> = Exit.Success<A> | Exit.Failure<E>;

declare namespace Exit {
  interface Success<A> {
    readonly _tag: "Success";
    readonly value: A;
  }
  
  interface Failure<E> {
    readonly _tag: "Failure";
    readonly cause: Cause<E>;
  }
}

// Fiber ID for tracking fibers
interface FiberId {
  readonly _tag: "FiberId";
  readonly id: number;
  readonly startTimeMillis: number;
}

Install with Tessl CLI

npx tessl i tessl/npm-effect

docs

concurrency-fibers.md

context-services.md

data-structures.md

effect-core.md

error-observability.md

function-utilities.md

index.md

layer-system.md

schema-validation.md

streaming.md

tile.json