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.invalidate
has been added, for invalidating a resource at the given key.RcMap.touch
has 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"))
awaitEmpty
has been added, which allows you to wait for all contained fibers to complete.makeRuntimePromise
&runtimePromise
have 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)})
.toValues
has been added toHashMap
andHashSet
, which allows you to get an Array of their values.HashMap.some
has 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.void
has been added, which is anEither<void, never>
.DateTime.toUtc
has been added, for converting anyDateTime
object to aDateTime.Utc
instance.Trie
type variance has been relaxed to be covariant.Differ
now implements thePipeable
interface.
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!