Skip to content

Effect 3.7 (Release)

Effect 3.7 has been released! This release includes a number of new features and improvements. Here’s a summary of what’s new:

The HttpApi family of modules provide a declarative way to define HTTP APIs.

These modules are still experimental and subject to change, so give them a try and post your feedback on the Effect Discord.

For more infomation see the README for the @effect/platform package:
https://github.com/Effect-TS/effect/blob/main/packages/platform/README.md

Effect.bindAll combines Effect.all with Effect.bind, to allow you to combine multiple effects inside of a do notation pipeline.

1
import { Effect } from "effect"
2
3
const result = Effect.Do.pipe(
4
Effect.bind("x", () => Effect.succeed(2)),
5
Effect.bindAll(
6
({ x }) => ({
7
a: Effect.succeed(x + 1),
8
b: Effect.succeed("foo"),
9
}),
10
{ concurrency: 2 },
11
),
12
)
13
assert.deepStrictEqual(Effect.runSync(result), {
14
x: 2,
15
a: 3,
16
b: "foo",
17
})

Stream.race takes two streams, and the first stream to emit an item will be elected as the winner and continue to emit items. The other stream will be interrupted.

1
import { Stream, Schedule, Console, Effect } from "effect"
2
3
const stream = Stream.fromSchedule(Schedule.spaced('2 millis')).pipe(
4
Stream.race(Stream.fromSchedule(Schedule.spaced('1 millis'))),
5
Stream.take(6),
6
Stream.tap(n => Console.log(n))
7
)
8
9
Effect.runPromise(Stream.runDrain(stream))
10
// Output each millisecond from the first stream, the other stream is interrupted
11
// 0
12
// 1
13
// 2
14
// 3
15
// 4
16
// 5

Use Config.nonEmptyString to create a Config that is guaranteed to be a non-empty string. If the config value is present but is empty, Config.withDefault can be used to provide a fallback value.

In the case you would like Fiber interrupts to be propogated to Fiber{Handle,Set,Map}.join, you can now use the propagateInterruption option.

1
import { Effect, FiberHandle } from "effect"
2
3
Effect.gen(function*() {
4
const handle = yield* FiberHandle.make()
5
6
// run a fiber and propagate interrupts
7
yield* FiberHandle.run(handle, Effect.interrupt, {
8
propagateInterruption: true
9
})
10
11
// this will now receive the interrupt
12
yield* FiberHandle.join(handle)
13
})

Previously Fiber.awaitAll would return a void result.

Now Fiber.awaitAll will return an Array<Exit<A, E>>, so you can inspect the results of the completed fibers.

The following apis will now preserve non-empty array types:

  • Array.modify
  • Array.modifyOption
  • Array.replace
  • Array.replaceOption

Previously, when using apis like Effect.forEach with concurrency, the Scope finalizer concurrency would be automatically adjusted to match.

In some scenarios this could cause finalizers to leak, so now the behavior must be explicitly requested using the concurrentFinalizers option.

1
import { Effect } from "effect"
2
3
Effect.forEach([1, 2, 3], (n) => Effect.succeed(n), {
4
concurrency: "unbounded",
5
concurrentFinalizers: true
6
})

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!