Having met Effect.zip (39)
and Effect.zipLeft (40)
, perhaps you won’t be surprised to learn that Effect.zipRight (41)
also exists.
Effect.zipRight runs both Effects in some arbitrary order (either sequentially or concurrently), just like Effect.zip (39)
. Its result type is the result type of the second operation. It discards the result of the first effect, which is a little like Effect.flatMap (6)
.
We can use Effect.zipRight to run “before-effects”. This might include things like validation.
const validateForm = ( _form: AddUserForm): Effect.Effect<void, ValidationError> => Effect.succeed("ok");
const addUser = (form: AddUserForm) => validateForm(form).pipe( Effect.zipRight(Api.post("/v1/users", form)), Effect.tap((res) => Router.redirect(`/users/${res.id}`)) );We can also use it in places where the next step does not rely on the result of the previous one. This is common in testing, where you want to assert that some action had the expected side effect. Here is an example where we are testing Api.post("/v1/users", ...).
const testNewlyCreatedUserAppearsInList = Api.post("/v1/users", { username: "bob", password: "bob123", confirmPassword: "bob123",}).pipe( Effect.zipRight(Api.get<User[]>("/v1/users")), Effect.flatMap((users) => Expect.contains(users, (user) => user.username === "bob") ));We can implement “Effect.zipRight” in terms of other things. These implementations look very similar to what we saw in Effect.zipLeft (40)
. The only difference is the return type.
type ZipRight = <B>( that: Effect.Effect<B>) => <A>(self: Effect.Effect<A>) => Effect.Effect<B>;
const zipRight: ZipRight = (that) => (self) => self.pipe( Effect.zip(that), Effect.map(([_a, b]) => b) );
type ZipRightSelfFirst = <A, B>( self: Effect.Effect<A>, that: Effect.Effect<B>) => Effect.Effect<B>;
const zipRightSelfFirst: ZipRightSelfFirst = (self, that) => self.pipe(zipRight(that));
const zipRightFlatMap: ZipRight = (that) => (self) => Effect.flatMap(self, (_a) => that);
const zipRightYield: ZipRight = (that) => (self) => Effect.gen(function* () { yield* self; const b = yield* that; return b; });Let’s recap:
Effect.zipRightcombines two effects (sequentially or concurrently)Effect.zipRightdiscards the left return valueEffect.zipRightis like a mix ofEffect.flatMap(6) andEffect.zip(39)- You don’t need to memorise or use every function in the Effect standard library!