This Week in Effect - 2024-02-02

Feb 2nd, 2024

Hi Effecters! Welcome to the very first This Week In Effect (TWIE). 

We’re proud to present you with this new format created to help you keep track of everything that is going on inside our Community and the Effect Ecosystem.

If it’s your first time here, Effect is a powerful TypeScript library designed to help developers create complex, synchronous, and asynchronous programs. One of the key features that sets Effect apart is how it leverages structured concurrency to provide features such as async cancellation and safe resource management, making it easier to build robust, scalable, and efficient programs.

To get started, below you’ll find our quick-start guide and documentation that will be your first step in your Effect journey. Enjoy!

Effect quick-start guide

Effect docs

Overview of TWIE

Before we get into what happened in the last week in our Community, we would like to say a few words about TWIE. 

We’re happy to witness the community growing so fast, with more and more people adopting Effect, and we understand that it might not be that easy keeping up with everything that is going on in the Effect Ecosystem:

  • Our Discord server reached 1850+ members a few days ago and the engagement is at an all-time high.
  • We’re approaching our very first Effect Days Conference in Vienna on February 23, 2024, and lots of new content is coming up.
  • All projects around Effect are receiving key updates and there has been a lot of activity on GitHub.

So, we wanted to make it easy for you to find all the info you need to fully enjoy your Effect journey!

And, that’s why we created TWIE – a weekly update to inform you about key events about Effect in the previous week, both from the community (Discord discussions, X posts, YouTube content etc.) and from a technical standpoint.

In this way, we want to help you stay on track with everything happening in the Effect Ecosystem and actively engage with our community.

So, let’s start!

Technology

Lists all the features, bug fixes, and changes (sometimes breaking) of this week.

General Chores

This adds provenance for publishing packages.

Effect Core

Add JSDoc documentation for Effect.intoDeferred

Improves performance of computing a FiberId hash by caching the computation

Use TimeoutException for timeout, previously timeout used NoSuchElementException and it proved to be confusing and error-prone when using combinators such as Effect.optionFromOptional to recover from such exceptions.

The following code is now valid:

ts
import { Effect } from "effect"
const recoverFromTimeout = Effect.sleep("2 seconds").pipe(
Effect.timeout("1 seconds"),
Effect.catchTag("TimeoutException", () => Effect.log("The program timed out"))
)
ts
import { Effect } from "effect"
const recoverFromTimeout = Effect.sleep("2 seconds").pipe(
Effect.timeout("1 seconds"),
Effect.catchTag("TimeoutException", () => Effect.log("The program timed out"))
)

With this change we remove the Data type and we make Equal & Hash implicit traits.

The main reason is that Data<A> was structurally equivalent to A & Equal but extending Equal doesn't mean that the equality is implemented by-value, so the type was simply adding noise without gaining any level of safety.

The module Data remains unchanged at the value level, all the functions previously available are supposed to work in exactly the same manner.

At the type level instead the functions return Readonly variants, so for example we have:

ts
import { Data } from "effect";
const obj = Data.struct({
a: 0,
b: 1,
});
ts
import { Data } from "effect";
const obj = Data.struct({
a: 0,
b: 1,
});

will have the obj typed as:

ts
declare const obj: {
readonly a: number;
readonly b: number;
};
ts
declare const obj: {
readonly a: number;
readonly b: number;
};

Improves naming of methods within the ReadonlyRecord module. Specifically, it renames ReadonlyRecord.upsert to ReadonlyRecord.set and ReadonlyRecord.update to ReadonlyRecord.replace. It also adds a new ReadonlyRecord.modify combinator that can be used to apply a function to the value of a ReadonlyRecord at a specific key.

Effect Schema

Adds a new section to the project README that explains the annotations feature by showing how to customize the generation of Arbitrary<A> instances.

Reorganizes overloads in Schema.optional to improve development experience when specifying defaults.

Improves generation of Equivalence supporting cases where schemas include transformations. Namely the following code:

ts
import { Schema } from "@effect/schema"
const schema = S.NumberFromString
const equivalence = E.make(schema)
ts
import { Schema } from "@effect/schema"
const schema = S.NumberFromString
const equivalence = E.make(schema)

No longer throws an error.

Add option to preserve excess properties when parsing, the feature is described in detail in the issue and can be summarized as:

ts
const data = S.parseSync({
foo: S.string
})({
foo: 'ok',
bar: 'ok'
})
ts
const data = S.parseSync({
foo: S.string
})({
foo: 'ok',
bar: 'ok'
})

The above code will strip the bar property as it is not defined in the schema, with the additional option as below:

ts
const data = S.parseSync({
foo: S.string
})({
foo: 'ok',
bar: 'ok'
}, {
onExcessProperty: "preserve"
})
ts
const data = S.parseSync({
foo: S.string
})({
foo: 'ok',
bar: 'ok'
}, {
onExcessProperty: "preserve"
})

The excess property is no longer removed.

Swaps the order of type parameters to simplify explicit type definitions, namely Schema<R, I, A> becomes Schema<A, I = A, R = never> this change also enables us to specify defaults for type parameters.

This enables to type simple schemas as:

ts
import { Schema } from "@effect/schema"
declare const number: Schema<number>
ts
import { Schema } from "@effect/schema"
declare const number: Schema<number>

and most importantly enables to ignore context when not needed like:

ts
import { Schema } from "@effect/schema"
declare const numberFromString: Schema<number, string>
ts
import { Schema } from "@effect/schema"
declare const numberFromString: Schema<number, string>

instead of being forced to write every parameter always like:

ts
import { Schema } from "@effect/schema"
declare const number: Schema<never, number, number>
ts
import { Schema } from "@effect/schema"
declare const number: Schema<never, number, number>

Effect Platform

Ensuring that fibers forked in uninterruptible regions are able to be interrupted.

Use Proxy for platform schema Transferable.

Adds support for URL objects in HTTP Client, the following code is now valid:

ts
import { HttpClient } from "@effect/platform"
import { Effect } from "effect"
const request = HttpClient.request.get(
new URL("https://www.google.com/")
).pipe(
HttpClient.client.fetchOk(),
Effect.flatMap((_) => _.text)
)
ts
import { HttpClient } from "@effect/platform"
import { Effect } from "effect"
const request = HttpClient.request.get(
new URL("https://www.google.com/")
).pipe(
HttpClient.client.fetchOk(),
Effect.flatMap((_) => _.text)
)

Removes re-exports from @effect/platform-* packages and improves naming of specialized modules, generic modules like HttpClient can now be imported only from @effect/platform and specific modules like NodeRuntime can be imported from the specific platform package (in this case @effect/platform-node).

ts
import { Runtime } from "@effect/platform-node"
ts
import { Runtime } from "@effect/platform-node"

becomes:

ts
import { NodeRuntime } from "@effect/platform-node"
ts
import { NodeRuntime } from "@effect/platform-node"

and:

ts
import { HttpClient } from "@effect/platform-node"
ts
import { HttpClient } from "@effect/platform-node"

becomes:

ts
import { HttpClient } from "@effect/platform"
ts
import { HttpClient } from "@effect/platform"

Fixes encoding of Transferable schemas, breaking because it includes a type-level change.

Effect Experimental

Ensuring that fibers forked in uninterruptible regions are able to be interrupted.

Effect CLI

Ensures proper error reporting when a single input is provided to a variadic option. Prior, the check was silently skipped.

Fixes the README to update:

  • introduction of the executable parameter as CLI no longer needs to slice process.argv and automatically deals with executable path;
  • adds missing Args from the README example.

Community

Guess what?! We welcomed 22 new Effecters last week! Thank you for joining the community and we look forward to your active participation in our ever-growing family!

Effect Days Update

Hear, hear! A big announcement from Vienna!

We've opened up 5 more spots for our Effect Days workshops on Feb 22nd! Both workshop and conference tickets are quickly running out, so don't miss the opportunity to grab your own!

The Conference is quickly approaching, and we presented our final speaker: Tim Smart, Effect Core Contributor and founding engineer of Effectful Technologies!

So, here you can find our full speakers lineup for Vienna: Speakers

Moreover, as the 23rd come closer, our speakers are giving a a short video sneak peek of their speeches.

Here you'll discover the one from Antoine Coulon:

and from Mattia Manzati:

Closing Notes

That's all for this week. Thank you for being a vital part of our community. Your feedback and requests are highly valued as we fine-tune this new format. Feel free to share your thoughts, and we'll do our best to tailor it to the needs of our community.

The Effect Community Team


Related Posts