Skip to content

Effect 3.9 (Release)

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

To make the creation of services in Effect easier, the Effect.Service api has been introduced.

It allows you to define both a Context.Tag and a Layer for a service in one pass, optionally giving you the ability to provide any dependencies at the same time.

1
import { FileSystem } from "@effect/platform"
2
import { NodeFileSystem } from "@effect/platform-node"
3
import type { Layer } from "effect"
4
import * as Effect from "effect/Effect"
5
6
export class Cache extends Effect.Service<Cache>()("app/Cache", {
7
// define how to create the service
8
// You can also use the "scoped", "sync" or "succeed" keys to create your service
9
effect: Effect.gen(function* () {
10
const fs = yield* FileSystem.FileSystem
11
const lookup = (key: string) => fs.readFileString(`cache/${key}`)
12
return { lookup } as const
13
}),
14
// provide dependencies
15
dependencies: [NodeFileSystem.layer]
16
}) {}
17
18
// Layer for use in the application
19
const layer: Layer.Layer<Cache> = Cache.Default
20
21
// Layer without dependencies provided
22
const layerNoDeps: Layer.Layer<Cache, never, FileSystem.FileSystem> =
23
Cache.DefaultWithoutDependencies
24
25
// `Cache` type also represents the service itself
26
declare const cache: Cache
27
cache.lookup("foo")

The Effect.provide & Layer.provide apis can now accept multiple layers to be provided.

1
someEffect.pipe(Effect.provide([layer1, layer2, layer3]))

You can now provide a ManagedRuntime to an effect, allowing you to use the services from the ManagedRuntime inside of the effect.

1
import { Effect, Layer, ManagedRuntime } from "effect"
2
3
const runtime = ManagedRuntime.make(Layer.empty)
4
5
someEffect.pipe(Effect.provide(runtime))

If you use a NonEmptyArray with Effect.mapAccum or Array.mapAccum, the result will now be typed as a NonEmptyArray.

You can use this api to determine if a value is a RegExp.

1
import { Predicate } from "effect"
2
3
assert.deepStrictEqual(Predicate.isRegExp(/a/), true)
4
assert.deepStrictEqual(Predicate.isRegExp("a"), false)

Tuple.map can be used to transform each element of a tuple using a function.

1
import { pipe, Tuple } from "effect"
2
3
const result = pipe(
4
// ^? [string, string, string]
5
["a", 1, false] as const,
6
Tuple.map((el) => {
7
// ^? "a" | 1 | false
8
return el.toString().toUpperCase()
9
})
10
)
11
assert.deepStrictEqual(result, ["A", "1", "FALSE"])

This api can be used to add elements to the end of an array until it reaches the desired length.

1
import { Array } from "effect"
2
3
const arr = [1, 2, 3]
4
const result = Array.pad(arr, 6, 0)
5
assert.deepStrictEqual(result, [1, 2, 3, 0, 0, 0])

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!