As we add more steps to pipe
the code starts to become less readable.
const main = fetchRequest.pipe(
Effect.filterOrFail(
(response) => response.ok,
() => new FetchError()
),
Effect.flatMap(jsonResponse),
Effect.catchTags({
FetchError: () => Effect.succeed("Fetch error"),
JsonError: () => Effect.succeed("Json error"),
})
);
We went from a simple if
check, to a scary looking filterOrFail
with two parameters and more lines of code.
Fear not! There is a solution for this in effect called Effect.gen
:
const main = Effect.gen(function* () {
const response = yield* fetchRequest;
if (!response.ok) {
return yield* new FetchError();
}
return yield* jsonResponse(response);
});
If you look closely, this is very similar to a normal async
/await
typescript function:
const fetchRequest = () => fetch("https://pokeapi.co/api/v2/pokemon/garchomp/");
const jsonResponse = (response: Response) => response.json();
const main = async () => {
const response = await fetchRequest();
if (!response.ok) {
throw new FetchError();
}
return await jsonResponse(response);
};
Take this and change:
async
withEffect.gen
- Arrow function
() =>
with a generator functionfunction* ()
await
andthrow
withyield*
const main = async () => {
const response = await fetchRequest();
if (!response.ok) {
throw new FetchError();
}
return await jsonResponse(response);
};
// 👆 Spot the differences 👇
const main = Effect.gen(function* () {
const response = yield* fetchRequest;
if (!response.ok) {
return yield* new FetchError();
}
return yield* jsonResponse(response);
});
How generators work
No need to learn the details of how this works to use effect. In fact, this is merely an implementation detail.
For reference, Effect.gen
uses a javascript feature called Generator functions.
This works in combination to the Iterator protocol to allow effect to track errors and success at every step in the function.
For what concerns us, this is a convenient way to write more concise and better-looking effect code, while keeping all the benefits of error tracking.
I suggest to favor
Effect.gen
overpipe
for most use cases. That's what I do in my code as well 💁🏼♂️From now on we are going to work with
Effect.gen
instead ofpipe
when possible.