Effect 3.13 (Release)
Effect 3.13 has been released! This release includes a number of new features and improvements. Here’s a summary of what’s new:
This API allows you to generate a Standard Schema v1 object from an Effect Schema.
import { Schema } from "effect"
const schema = Schema.Struct({ name: Schema.String})
// ┌─── StandardSchemaV1<{ readonly name: string; }>// ▼const standardSchema = Schema.standardSchemaV1(schema)Effect.fn has been improved to allow you to access the function arguments inside any of the pipeline functions.
import { Effect } from "effect"
const fn = Effect.fn("my function")( function* (n: number) { yield* Effect.log(`n is ${n}`) }, // you can now access the arguments here (effect, n) => Effect.annotateLogs(effect, { n }))RcMap.invalidatehas been added, for invalidating a resource at the given key.RcMap.touchhas been added, for refreshing the idle timeout of a resource at the given key.
import { Effect, RcMap } from "effect"
Effect.gen(function* () { const map = yield* RcMap.make({ lookup: (n: number) => Effect.succeed(n), idleTimeToLive: "1 minute" })
// retrieve the resource at key 1 yield* Effect.scoped(RcMap.get(map, 1))
// refresh the idle timeout of the resource at key 1 yield* RcMap.touch(map, 1)
// invalidate the resource at key 1 yield* RcMap.invalidate(map, 1)})This function transforms an Option<Effect<A, E, R>> into an
Effect<Option<A>, E, R>. If the Option is None, the resulting Effect
will immediately succeed with a None value. If the Option is Some, the
inner Effect will be executed, and its result wrapped in a Some.
import { Effect, Option } from "effect"
// ┌─── Option<Effect<number, never, never>>// ▼const maybe = Option.some(Effect.succeed(42))
// ┌─── Effect<Option<number>, never, never>// ▼const result = Effect.transposeOption(maybe)
console.log(Effect.runSync(result))// Output: { _id: 'Option', _tag: 'Some', value: 42 }Effect.filterEffectOrElse filters an effect with an effectful predicate, falling back to an alternative
effect if the predicate fails.
import { Effect, pipe } from "effect"
// Define a user interfaceinterface User { readonly name: string}
// Simulate an asynchronous authentication functiondeclare const auth: () => Promise<User | null>
const program = pipe( Effect.promise(() => auth()), // Use filterEffectOrElse with an effectful predicate Effect.filterEffectOrElse({ predicate: (user) => Effect.succeed(user !== null), orElse: (user) => Effect.fail(new Error(`Unauthorized user: ${user}`)) }))This new api allows you to filter an effect with an effectful predicate, failing with a custom error if the predicate fails.
import { Effect, pipe } from "effect"
// Define a user interfaceinterface User { readonly name: string}
// Simulate an asynchronous authentication functiondeclare const auth: () => Promise<User | null>
const program = pipe( Effect.promise(() => auth()), // Use filterEffectOrFail with an effectful predicate Effect.filterEffectOrFail({ predicate: (user) => Effect.succeed(user !== null), orFailWith: (user) => new Error(`Unauthorized user: ${user}`) }))Effect.whenLogLevel allows you to conditionally execute an effect when the specified log level is enabled.
import { Effect } from "effect"
// Sleep for 1 second only when the minimum log level is "Debug" or lowerEffect.sleep("1 second").pipe(Effect.whenLogLevel("Debug"))awaitEmptyhas been added, which allows you to wait for all contained fibers to complete.makeRuntimePromise&runtimePromisehave been added, which allows you to run effects and get back a promise that will resolve when the effect completes.
import { Effect, FiberSet } from "effect"
Effect.gen(function* () { const set = yield* FiberSet.make<number>()
// create a runPromise function from a FiberSet const runPromise = yield* FiberSet.runtimePromise(set)
// returns `Promise<number>` runPromise(Effect.succeed(1))
// wait for all the fibers to complete yield* FiberSet.awaitEmpty(set)}).toValueshas been added toHashMapandHashSet, which allows you to get an Array of their values.HashMap.somehas been added, which allows you to check if any of the entries satisfy a predicate.
Layer.updateService has been added, which allows you to update a specific service during Layer creation.
import { Effect, Layer } from "effect"
class MyService extends Effect.Service<MyService>()("MyService", { succeed: { name: "Tim" as string }}) {}
declare const RequiresMyService: Layer.Layer<never, never, MyService>
const UpdateMyService = RequiresMyService.pipe( // update the implementation of `MyService` before providing it to `RequiresMyService` Layer.updateService(MyService, (obj) => ({ ...obj, name: "John" })))Either.voidhas been added, which is anEither<void, never>.DateTime.toUtchas been added, for converting anyDateTimeobject to aDateTime.Utcinstance.Trietype variance has been relaxed to be covariant.Differnow implements thePipeableinterface.
There were several other smaller changes made. Take a look through the CHANGELOG to see them all: CHANGELOG.
Don’t forget to join our Discord Community to follow the last updates and discuss every tiny detail!