Skip to content

Effect 3.6 (Release)

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

The DateTime module provides functionality for working with time, including support for time zones and daylight saving time.

It has two main data types: DateTime.Utc and DateTime.Zoned.

A DateTime.Utc represents a time in Coordinated Universal Time (UTC), and a DateTime.Zoned contains both a UTC timestamp and a time zone.

There is also a CurrentTimeZone service, for setting a time zone contextually.

1
import { DateTime, Effect } from "effect"
2
3
Effect.gen(function* () {
4
// Get the current time in the current time zone
5
const now = yield* DateTime.nowInCurrentZone
6
7
// Math functions are included
8
const tomorrow = DateTime.add(now, { days: 1 })
9
10
// Convert to a different time zone
11
// The UTC portion of the `DateTime` is preserved and only the time zone is
12
// changed
13
const sydneyTime = tomorrow.pipe(
14
DateTime.unsafeSetZoneNamed("Australia/Sydney"),
15
)
16
}).pipe(DateTime.withCurrentZoneNamed("America/New_York"))

Stream.asyncPush can be used to create a Stream from an external push-based resource.

You can customize the buffer size and strategy by passing an object as the second argument with the bufferSize and strategy fields.

1
import { Effect, Stream } from "effect";
2
3
Stream.asyncPush<string>(
4
(emit) =>
5
Effect.acquireRelease(
6
Effect.gen(function* () {
7
yield* Effect.log("subscribing");
8
return setInterval(() => emit.single("tick"), 1000);
9
}),
10
(handle) =>
11
Effect.gen(function* () {
12
yield* Effect.log("unsubscribing");
13
clearInterval(handle);
14
}),
15
),
16
{ bufferSize: 16, strategy: "dropping" },
17
);

To access the fully typed keys of a struct, you can use the Struct.keys function.

1
import { Struct } from "effect"
2
3
const symbol: unique symbol = Symbol()
4
5
const value = {
6
a: 1,
7
b: 2,
8
[symbol]: 3
9
}
10
11
const keys: Array<"a" | "b"> = Struct.keys(value)

The @effect/sql-kysely package provides @effect/sql integration with the kysely query builder apis.

1
// create a Tag with your `Database` type
2
class KyselyDB extends Context.Tag("KyselyDB")<KyselyDB, Kysely<Database>>() {}
3
4
Effect.gen(function*(_) {
5
// access the service and execute queries
6
const db = yield* KyselyDB
7
8
yield* db.schema
9
.createTable("users")
10
.addColumn("id", "integer", (c) => c.primaryKey().autoIncrement())
11
.addColumn("userName", "text", (c) => c.notNull())
12
13
const inserted = yield* db.insertInto("users").values({ userName: "Alice" }).returningAll()
14
const selected = yield* db.selectFrom("users").selectAll()
15
const updated = yield* db.updateTable("users").set({ userName: "Bob" }).returningAll()
16
const deleted = yield* db.deleteFrom("users").returningAll()
17
})

This api allows you to randomly select an item from an Iterable.

Unless the Iterable is “NonEmpty”, then the Effect can fail with a Cause.NoSuchElementException.

1
import { Random } from "effect"
2
3
Effect.gen(function* () {
4
const randomItem = yield* Random.choice([1, 2, 3])
5
console.log(randomItem)
6
})

If the onlyEffect option for Effect.tap is set to true, then it will ensure the side effect only uses Effect’s.

This can be useful when you want to add strictness to your program.

Refinements can now be used with Predicate.tuple and Predicate.struct to narrow the resulting type.

1
import { Predicate } from "effect"
2
3
const isTrue = (u: unknown): u is true => u === true
4
5
// will narrow the type to { isTrue: true }
6
Predicate.struct({ isTrue })

Some new lifetime hook apis have been added to the Stream module:

  • Stream.onStart - run an effect when the stream starts
  • Stream.onEnd - run an effect when the stream ends without error

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!