Async Handling
Mix sync + async validation and effects with Result pipelines.
When to use async pipelines
Use async pipelines when a step needs IO (API calls, DB checks, file reads) but you still want the same short-circuiting behavior as sync Result chains.
The key rule: call .toPromise() at the end of any chain that contains async operations.
Wrapping Async Code
Safe fetch with tryAsyncCatch
Wrap external APIs that might throw:
import { } from "@carbonteq/fp";
type = { : string; : string };
async function (: string): <<, Error>> {
return .(
async () => {
const = await (`/api/users/${}`);
if (!.) throw new (`HTTP ${.}`);
return .() as <>;
},
() => ( instanceof ? : new (())),
).();
}
const = await ("123");
.(); // Result.Ok({ id, name }) or Result.Err(Error)Chain async operations with flatMap
import { } from "@carbonteq/fp";
type = { : string; : number };
type = { : string };
declare function (: string): <>;
declare function (: ): <>;
async function (: string): <<string, Error>> {
return .(() => (), () => as Error)
.((: ) =>
.(() => (), () => as Error),
)
.((: ) => .)
.();
}Mixed Sync + Async Validation
The .validate() operator handles both sync and async validators:
import { } from "@carbonteq/fp";
type = { : string; : string };
const = (: ) =>
..("@") ? .() : .("Invalid email");
const = (: ) =>
.. >= 8 ? .() : .("Password too short");
declare function (: string): <boolean>;
async function (: ): <<, string>> {
const = await (.);
return ? .("Email taken") : .();
}
async function (: ) {
return .()
.([, , ])
.();
}Async Side Effects
Use tap and tapErr for logging or fire-and-forget operations:
import { } from "@carbonteq/fp";
type = { : string; : string };
declare function (: ): <, Error>;
declare function (: ): <<, Error>>;
declare function (: string, : string): void;
async function (: ): <<, Error>> {
return .()
.()
.((: ) => .(`Validated: ${.}`))
.()
.((: ) => (., `Order ${.} confirmed`))
.((: Error) => .(`Failed: ${.}`))
.();
}Fallback Chains
Use orElse to try alternatives when the primary source fails:
import { } from "@carbonteq/fp";
type = { : string; : string };
declare function (: string): <, Error>;
declare function (: string): <, Error>;
function (): {
return { : "guest", : "guest-token" };
}
function (: string): <, Error> {
return ()
.((: Error) => .(`Redis miss: ${.}`))
.(() => ())
.((: Error) => .(`DB miss: ${.}`))
.(() => .(()));
}Parallel Async Operations
All must succeed with Result.all
import { } from "@carbonteq/fp";
type = { : string };
type = { : string };
declare function (: string): <<, Error>>;
declare function (: string): <<, Error>>;
async function (: string) {
const [, ] = await .([
(),
(),
]);
return .(, ).(([, ]) => ({
: .,
: .,
}));
}First success with Result.any
import { } from "@carbonteq/fp";
type = { : string };
declare function (): <, Error>;
declare function (): <, Error>;
declare function (): <, Error>;
function (): <, Error[]> {
return .((), (), ());
}Tips
| Pattern | When to use |
|---|---|
tryAsyncCatch | Wrap code that throws exceptions |
validate([...]) | Multiple guards (sync or async) with error accumulation |
flatMap(asyncFn) | Chain async operations that return Result |
tap / tapErr | Side effects (logging, metrics, emails) |
orElse | Fallback chains (cache → DB → default) |
Result.all | Parallel ops where all must succeed |
Result.any | Parallel ops where first success wins |
toPromise() | Always call at the end of async chains |