• 日本語
  • 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: RequestInfo | URL, init?: RequestInit): Promise<Response>
    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
    ),
    );