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
);

Resultpipe を組み合わせる

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.@example
import { 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: boolean

The 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.

MDN Reference

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
),
);