#pipe 関数の扱い方
pipe 関数は @praha/byethrow の中核をなす機能の一つです。
複数の操作を読みやすい左から右への方式で連結できます。
#pipe とは?
pipe は初期値を受け取り、一連の関数に順番に渡していきます。
各関数は前の関数の出力を受け取ります。
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, // 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&#なぜ pipe を使うのか?
#pipe を使わない場合
ネストした関数呼び出しは読みにくいです。
// ❌ 読みにくい - 内側から外側へ読む必要がある
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));中間変数を使うと冗長になります。
// ❌ 変数が多すぎる
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 );#pipe を使う場合
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,
(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
);#Result と pipe を組み合わせる
pipe の真価は Result と一緒に使うときに発揮されます。
@praha/byethrow のすべての変換関数は 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 }#pipe の非同期処理
パイプ内のいずれかの関数が Promise を返すと、結果は 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 ),
);