#Pipe Basics
The pipe function is the heart of @praha/byethrow. It allows you to chain multiple operations together in a readable, left-to-right manner.
#What is pipe?
pipe takes an initial value and passes it through a series of functions, where each function receives the output of the previous one:
import { import Result Result } from '@praha/byethrow';
const const result: string result = import Result Result .const pipe: <number, number, number, string>(a: number, ab: (a: number) => number, bc: (b: number) => number, cd: (c: number) => string) => string (+25 overloads) pipe (
5, // Start with 5
(x: number x ) => x: number x + 1, // 5 + 1 = 6
(x: number x ) => x: number x * 2, // 6 * 2 = 12
(x: number x ) => `Result: ${x: number x }` // 'Result: 12'
);
// 'Result: 12&#Why Use pipe?
#Without pipe
Nested function calls are hard to read:
// ❌ Hard to read - inside out
const const result: string result = const format: (x: number) => string format (const multiply: (a: number, b: number) => number multiply (const add: (a: number, b: number) => number add (5, 1), 2));Or intermediate variables are verbose:
// ❌ Too many variables
const const step1: number step1 = const add: (a: number, b: number) => number add (5, 1);
const const step2: number step2 = const multiply: (a: number, b: number) => number multiply (const step1: number step1 , 2);
const const result: string result = const format: (x: number) => string format (const step2: number step2 );#With pipe
import { import Result Result } from '@praha/byethrow';
// ✅ Clear, left-to-right flow
const const result: string result = import Result Result .const pipe: <number, number, number, string>(a: number, ab: (a: number) => number, bc: (b: number) => number, cd: (c: number) => string) => string (+25 overloads) pipe (
5,
(x: number x ) => const add: (a: number, b: number) => number add (x: number x , 1),
(x: number x ) => const multiply: (a: number, b: number) => number multiply (x: number x , 2),
const format: (x: number) => string format
);#Using pipe with Results
The real power of pipe comes when working with Results. All the transformation functions in @praha/byethrow are designed to work with pipe:
import { import Result Result } from '@praha/byethrow';
const const result: Result.Result<number, never> result = import Result Result .const pipe: <Result.Result<10, never>, Result.Result<number, never>, Result.Result<number, never>>(a: Result.Result<10, never>, ab: (a: Result.Result<10, never>) => Result.Result<number, never>, bc: (b: Result.Result<number, never>) => Result.Result<number, never>) => Result.Result<number, never> (+25 overloads) pipe (
import Result Result .const succeed: <10>(value: 10) => Result.Result<10, never> (+1 overload) succeed (10),
import Result Result .const map: <Result.Result<10, never>, number>(fn: (a: 10) => number) => (result: Result.Result<10, never>) => Result.Result<number, never> (+1 overload) map ((x: 10 x ) => x: 10 x * 2),
import Result Result .const map: <Result.Result<number, never>, number>(fn: (a: number) => number) => (result: Result.Result<number, never>) => Result.Result<number, never> (+1 overload) map ((x: number x ) => x: number x + 5),
);
// { type: 'Success', value: 25 }#How pipe Handles Async
When any function in the pipe returns a Promise, the result becomes a Promise:
import { import Result Result } from '@praha/byethrow';
type type User = {
id: string;
name: string;
}
User = { id: string id : string; name: string name : string; };
const const fetchUser: (id: string) => Result.ResultAsync<User, string> fetchUser = async (id: string id : string): import Result Result .type ResultAsync<T, E> = Promise<Result.Result<T, E>>An asynchronous variant of
Result
, wrapped in a Promise.
@typeParamT - The type of the Success value.@typeParamE - The type of the Failure value.@exampleimport { Result } from '@praha/byethrow';
const fetchData = async (): Result.ResultAsync<string, Error> => {
try {
const data = await fetch('...');
return { type: 'Success', value: await data.text() };
} catch (err) {
return { type: 'Failure', error: err as Error };
}
};
@categoryCore Types ResultAsync <type User = {
id: string;
name: string;
}
User , string> => {
const const response: Response response = await function fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> (+1 overload) fetch (`/api/users/${id: string id }`);
if (!const response: Response response .Response.ok: booleanThe ok read-only property of the Response interface contains a Boolean stating whether the response was successful (status in the range 200-299) or not.
ok ) {
return import Result Result .const fail: <"User not found">(error: "User not found") => Result.Result<never, "User not found"> (+1 overload) fail ('User not found');
}
const const user: any user = await const response: Response response .Body.json(): Promise<any> json ();
return import Result Result .const succeed: <any>(value: any) => Result.Result<any, never> (+1 overload) succeed (const user: any user );
};
const const result: Result.Result<string, string> result = await import Result Result .const pipe: <Result.Result<"user-123", never>, Result.ResultAsync<User, string>, Result.ResultAsync<string, string>>(a: Result.Result<"user-123", never>, ab: (a: Result.Result<"user-123", never>) => Result.ResultAsync<User, string>, bc: (b: Result.ResultAsync<User, string>) => Result.ResultAsync<string, string>) => Result.ResultAsync<string, string> (+25 overloads) pipe (
import Result Result .const succeed: <"user-123">(value: "user-123") => Result.Result<"user-123", never> (+1 overload) succeed ('user-123'),
import Result Result .const andThen: <Result.Result<"user-123", never>, Result.ResultAsync<User, string>>(fn: (a: "user-123") => Result.ResultAsync<User, string>) => (result: Result.Result<"user-123", never>) => Result.ResultAsync<User, string> (+1 overload) andThen (const fetchUser: (id: string) => Result.ResultAsync<User, string> fetchUser ),
import Result Result .const map: <Result.ResultAsync<User, string>, string>(fn: (a: User) => string) => (result: Result.ResultAsync<User, string>) => Result.ResultAsync<string, string> (+1 overload) map ((user: User user ) => user: User user .name: string name ),
);