An Effect is a full description of a program. We can compose Effect with each other to build other Effect that describe more complex programs.
In this example we have 2 effects fetchRequest and jsonResponse:
fetchRequestreturns an effect that containsResponse- We want to extract
Responsefrom the first effect and provide it tojsonResponse
The problem is that we wrapped Response inside Effect (Effect<Response>). We cannot just "extract" Response anymore:
const fetchRequest = Effect.promise(() =>
fetch("https://pokeapi.co/api/v2/pokemon/garchomp/")
);
const response: Response = /// No way to directly access `Response` 😬Effects are computations. They don't hold the
Response.It is impossible to get the
Responseout of an effect because theResponsedoes not exist (yet).Evaluating the effect will result in a
Response.
Instead effect provides functions that describe what's the next step to execute based on the value from the previous effect(s).
flatMap: Get value and return Effect
Effect.flatMap allows to access the result of an effect and chain another Effect:
- First parameter:
Effectfrom where we want to extract the value - Second parameter: function that gives access to the first
Effectparameter and returns anotherEffect
const fetchRequest = Effect.promise(() =>
fetch("https://pokeapi.co/api/v2/pokemon/garchomp/")
);
const main = Effect.flatMap(
fetchRequest, // 👈 Extract value from `fetchRequest`
(response) => // 👈 Access `Response` and return another `Effect`
);With Effect.flatMap we can chain jsonResponse since we get access to response:
/// 👇 `Effect<Response>`
const fetchRequest = Effect.promise(() =>
fetch("https://pokeapi.co/api/v2/pokemon/garchomp/")
);
/// 👇 `Effect<unknown>` (return type of `jsonResponse`)
const main = Effect.flatMap(
fetchRequest,
(response) => jsonResponse(response)
);This may look weird. No more linear imperative code one line after the other, but instead using functions that take as input other functions and return functions 🙌
Bare with me for now, effect offers some way to write way better-looking code that we are going to introduce later.
We can then run the final program using runPromise:
runPromiseis the equivalent ofrunSyncbut for asynchronous programs
const fetchRequest = Effect.promise(() =>
fetch("https://pokeapi.co/api/v2/pokemon/garchomp/")
);
const jsonResponse = (response: Response) =>
Effect.promise(() => response.json());
const main = Effect.flatMap(
fetchRequest,
(response) => jsonResponse(response)
);
Effect.runPromise(main);We can even simplify the code to:
const fetchRequest = Effect.promise(() =>
fetch("https://pokeapi.co/api/v2/pokemon/garchomp/")
);
const jsonResponse = (response: Response) =>
Effect.promise(() => response.json());
const main = Effect.flatMap(
fetchRequest,
jsonResponse
);
Effect.runPromise(main);