• 日本語
  • 検証とエラーからの回復

    andThroughorThrough 関数を使うと、元の結果値を保持しながら、検証や回復のための追加計算を実行できます。

    andThrough - 変換なしの検証

    andThrough 関数は成功値を使って追加の計算を実行しますが、追加の計算が成功した場合は元の結果を返します。 元の結果または副作用の結果のいずれかが Failure の場合、その失敗が返されます。

    これは、成功時にメインの結果を変更せずに、バリデーションや副作用を実行する場合に便利です。

    基本的な使い方

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<5, "Must be > 0">
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<5, never>, Result.Result<5, "Must be > 0">>(a: Result.Result<5, never>, ab: (a: Result.Result<5, never>) => Result.Result<5, "Must be > 0">) => Result.Result<5, "Must be > 0"> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const succeed: <5>(value: 5) => Result.Result<5, never> (+1 overload)
    succeed
    (5),
    import Result
    Result
    .
    const andThrough: <Result.Result<5, never>, Result.Success<void> | Result.Failure<"Must be > 0">>(fn: (a: 5) => Result.Success<void> | Result.Failure<"Must be > 0">) => (result: Result.Result<5, never>) => Result.Result<5, "Must be > 0"> (+1 overload)
    andThrough
    ((
    value: 5
    value
    ) => {
    return 0 <
    value: 5
    value
    ?
    import Result
    Result
    .
    const succeed: () => Result.ResultFor<never, void, never> (+1 overload)
    succeed
    () :
    import Result
    Result
    .
    const fail: <"Must be > 0">(error: "Must be > 0") => Result.Result<never, "Must be > 0"> (+1 overload)
    fail
    ('Must be > 0');
    }), ); // { type: 'Success', value: 5 } - 元の値が保持される

    入力が Failure の場合

    入力が Failure の場合、andThrough は何もせず、Failure をそのまま返します。

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<never, "error" | "Must be > 0">
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<never, "error">, Result.Result<never, "error" | "Must be > 0">>(a: Result.Result<never, "error">, ab: (a: Result.Result<never, "error">) => Result.Result<never, "error" | "Must be > 0">) => Result.Result<never, "error" | "Must be > 0"> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const fail: <"error">(error: "error") => Result.Result<never, "error"> (+1 overload)
    fail
    ('error'),
    import Result
    Result
    .
    const andThrough: <Result.Result<never, "error">, Result.Success<void> | Result.Failure<"Must be > 0">>(fn: (a: never) => Result.Success<void> | Result.Failure<"Must be > 0">) => (result: Result.Result<never, "error">) => Result.Result<never, "error" | "Must be > 0"> (+1 overload)
    andThrough
    ((
    value: never
    value
    ) => {
    return 0 <
    value: never
    value
    ?
    import Result
    Result
    .
    const succeed: () => Result.ResultFor<never, void, never> (+1 overload)
    succeed
    () :
    import Result
    Result
    .
    const fail: <"Must be > 0">(error: "Must be > 0") => Result.Result<never, "Must be > 0"> (+1 overload)
    fail
    ('Must be > 0');
    }), ); // { type: 'Failure', error: 'error' }

    関数が Failure を返す場合

    副作用が Failure を返すと、その失敗が代わりに返されます。

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<-10, "Must be > 0">
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<-10, never>, Result.Result<-10, "Must be > 0">>(a: Result.Result<-10, never>, ab: (a: Result.Result<-10, never>) => Result.Result<-10, "Must be > 0">) => Result.Result<-10, "Must be > 0"> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const succeed: <-10>(value: -10) => Result.Result<-10, never> (+1 overload)
    succeed
    (-10),
    import Result
    Result
    .
    const andThrough: <Result.Result<-10, never>, Result.Success<void> | Result.Failure<"Must be > 0">>(fn: (a: -10) => Result.Success<void> | Result.Failure<"Must be > 0">) => (result: Result.Result<-10, never>) => Result.Result<-10, "Must be > 0"> (+1 overload)
    andThrough
    ((
    value: -10
    value
    ) => {
    return 0 <
    value: -10
    value
    ?
    import Result
    Result
    .
    const succeed: () => Result.ResultFor<never, void, never> (+1 overload)
    succeed
    () :
    import Result
    Result
    .
    const fail: <"Must be > 0">(error: "Must be > 0") => Result.Result<never, "Must be > 0"> (+1 overload)
    fail
    ('Must be > 0');
    }), ); // { type: 'Failure', error: 'Must be > 0' }

    例:複数のバリデーション

    よくある使い方として、値に対して複数のバリデーションを実行する例があります。

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    type
    type User = {
        name: string;
        age: number;
        email: string;
    }
    User
    = {
    name: string
    name
    : string;
    age: number
    age
    : number;
    email: string
    email
    : string };
    declare const
    const validateName: (user: User) => Result.Result<void, "Invalid name">
    validateName
    : (
    user: User
    user
    :
    type User = {
        name: string;
        age: number;
        email: string;
    }
    User
    ) =>
    import Result
    Result
    .
    type Result<T, E> = Result.Success<T> | Result.Failure<E>

    A union type representing either a success or a failure.

    @typeParamT - The type of the Success value.@typeParamE - The type of the Failure value.@example
    import { Result } from '@praha/byethrow';
    
    const doSomething = (): Result.Result<number, string> => {
      return Math.random() > 0.5
        ? { type: 'Success', value: 10 }
        : { type: 'Failure', error: 'Oops' };
    };
    @categoryCore Types
    Result
    <void, 'Invalid name'>;
    declare const
    const validateAge: (user: User) => Result.Result<void, "Invalid age">
    validateAge
    : (
    user: User
    user
    :
    type User = {
        name: string;
        age: number;
        email: string;
    }
    User
    ) =>
    import Result
    Result
    .
    type Result<T, E> = Result.Success<T> | Result.Failure<E>

    A union type representing either a success or a failure.

    @typeParamT - The type of the Success value.@typeParamE - The type of the Failure value.@example
    import { Result } from '@praha/byethrow';
    
    const doSomething = (): Result.Result<number, string> => {
      return Math.random() > 0.5
        ? { type: 'Success', value: 10 }
        : { type: 'Failure', error: 'Oops' };
    };
    @categoryCore Types
    Result
    <void, 'Invalid age'>;
    declare const
    const validateEmail: (user: User) => Result.Result<void, "Invalid email">
    validateEmail
    : (
    user: User
    user
    :
    type User = {
        name: string;
        age: number;
        email: string;
    }
    User
    ) =>
    import Result
    Result
    .
    type Result<T, E> = Result.Success<T> | Result.Failure<E>

    A union type representing either a success or a failure.

    @typeParamT - The type of the Success value.@typeParamE - The type of the Failure value.@example
    import { Result } from '@praha/byethrow';
    
    const doSomething = (): Result.Result<number, string> => {
      return Math.random() > 0.5
        ? { type: 'Success', value: 10 }
        : { type: 'Failure', error: 'Oops' };
    };
    @categoryCore Types
    Result
    <void, 'Invalid email'>;
    const
    const validateUser: (user: User) => Result.Result<User, "Invalid name" | "Invalid age" | "Invalid email">
    validateUser
    = (
    user: User
    user
    :
    type User = {
        name: string;
        age: number;
        email: string;
    }
    User
    ) =>
    import Result
    Result
    .
    const pipe: <Result.Result<User, never>, Result.Result<User, "Invalid name">, Result.Result<User, "Invalid name" | "Invalid age">, Result.Result<User, "Invalid name" | "Invalid age" | "Invalid email">>(a: Result.Result<User, never>, ab: (a: Result.Result<User, never>) => Result.Result<User, "Invalid name">, bc: (b: Result.Result<User, "Invalid name">) => Result.Result<User, "Invalid name" | "Invalid age">, cd: (c: Result.Result<...>) => Result.Result<...>) => Result.Result<...> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const succeed: <User>(value: User) => Result.Result<User, never> (+1 overload)
    succeed
    (
    user: User
    user
    ),
    import Result
    Result
    .
    const andThrough: <Result.Result<User, never>, Result.Result<void, "Invalid name">>(fn: (a: User) => Result.Result<void, "Invalid name">) => (result: Result.Result<User, never>) => Result.Result<User, "Invalid name"> (+1 overload)
    andThrough
    (
    const validateName: (user: User) => Result.Result<void, "Invalid name">
    validateName
    ),
    import Result
    Result
    .
    const andThrough: <Result.Result<User, "Invalid name">, Result.Result<void, "Invalid age">>(fn: (a: User) => Result.Result<void, "Invalid age">) => (result: Result.Result<User, "Invalid name">) => Result.Result<User, "Invalid name" | "Invalid age"> (+1 overload)
    andThrough
    (
    const validateAge: (user: User) => Result.Result<void, "Invalid age">
    validateAge
    ),
    import Result
    Result
    .
    const andThrough: <Result.Result<User, "Invalid name" | "Invalid age">, Result.Result<void, "Invalid email">>(fn: (a: User) => Result.Result<void, "Invalid email">) => (result: Result.Result<User, "Invalid name" | "Invalid age">) => Result.Result<User, "Invalid name" | "Invalid age" | "Invalid email"> (+1 overload)
    andThrough
    (
    const validateEmail: (user: User) => Result.Result<void, "Invalid email">
    validateEmail
    ),
    ); // すべてのバリデーションが通れば元のユーザーを返し、そうでなければ最初のエラーを返す

    orThrough - 元の失敗を保持した回復

    orThrough 関数は失敗からの回復を試みる追加の計算を実行しますが、回復が成功した場合は元の失敗を返します

    元の結果が Success の場合、関数を実行せずに即座に返されます。 元の結果が Failure の場合、エラー値で関数が実行されます。関数が Success を返すと、元の失敗が返されます。 関数が Failure を返すと、その新しい失敗が返されます。

    これは、失敗した操作からの回復(例:クリーンアップ、ロールバック)を試みながら、元のエラーを保持する場合に便利です。

    基本的な使い方

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<5, never>
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<5, never>, Result.Result<5, never>>(a: Result.Result<5, never>, ab: (a: Result.Result<5, never>) => Result.Result<5, never>) => Result.Result<5, never> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const succeed: <5>(value: 5) => Result.Result<5, never> (+1 overload)
    succeed
    (5),
    import Result
    Result
    .
    const orThrough: <Result.Result<5, never>, Result.Result<void, never>>(fn: (a: never) => Result.Result<void, never>) => (result: Result.Result<5, never>) => Result.Result<5, never> (+1 overload)
    orThrough
    ((
    error: never
    error
    ) => {
    // 失敗回復ロジックをここに return
    import Result
    Result
    .
    const succeed: () => Result.ResultFor<never, void, never> (+1 overload)
    succeed
    ();
    }), ); // { type: 'Success', value: 5 } - 成功はそのまま通過

    入力が Failure の場合

    入力が Failure の場合、orThrough は関数を実行しますが、元のエラーを保持します。

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<never, "error">
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<never, "error">, Result.Result<never, "error">>(a: Result.Result<never, "error">, ab: (a: Result.Result<never, "error">) => Result.Result<never, "error">) => Result.Result<never, "error"> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const fail: <"error">(error: "error") => Result.Result<never, "error"> (+1 overload)
    fail
    ('error'),
    import Result
    Result
    .
    const orThrough: <Result.Result<never, "error">, Result.Result<void, never>>(fn: (a: "error") => Result.Result<void, never>) => (result: Result.Result<never, "error">) => Result.Result<never, "error"> (+1 overload)
    orThrough
    ((
    error: "error"
    error
    ) => {
    // 失敗回復ロジックをここに return
    import Result
    Result
    .
    const succeed: () => Result.ResultFor<never, void, never> (+1 overload)
    succeed
    ();
    }), ); // 'Logging error: error' をログに出力し、{ type: 'Failure', error: 'error' } を返す

    関数が Failure を返す場合

    関数が Failure を返すと、その新しい失敗が元の失敗を置き換えます。

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<never, "original error" | "new error">
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<never, "original error">, Result.Result<never, "original error" | "new error">>(a: Result.Result<never, "original error">, ab: (a: Result.Result<never, "original error">) => Result.Result<never, "original error" | "new error">) => Result.Result<never, "original error" | "new error"> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const fail: <"original error">(error: "original error") => Result.Result<never, "original error"> (+1 overload)
    fail
    ('original error'),
    import Result
    Result
    .
    const orThrough: <Result.Result<never, "original error">, Result.Result<never, "new error">>(fn: (a: "original error") => Result.Result<never, "new error">) => (result: Result.Result<never, "original error">) => Result.Result<never, "original error" | "new error"> (+1 overload)
    orThrough
    ((
    error: "original error"
    error
    ) => {
    return
    import Result
    Result
    .
    const fail: <"new error">(error: "new error") => Result.Result<never, "new error"> (+1 overload)
    fail
    ('new error');
    }), ); // { type: 'Failure', error: 'new error' }

    例:クリーンアップを伴う回復

    よくある使い方として、クリーンアップを行いながら失敗した操作からの回復を試みる例があります。

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    declare const
    const uploadFile: (path: string, content: string) => Result.Result<void, "UploadFileFailed">
    uploadFile
    : (
    path: string
    path
    : string,
    content: string
    content
    : string) =>
    import Result
    Result
    .
    type Result<T, E> = Result.Success<T> | Result.Failure<E>

    A union type representing either a success or a failure.

    @typeParamT - The type of the Success value.@typeParamE - The type of the Failure value.@example
    import { Result } from '@praha/byethrow';
    
    const doSomething = (): Result.Result<number, string> => {
      return Math.random() > 0.5
        ? { type: 'Success', value: 10 }
        : { type: 'Failure', error: 'Oops' };
    };
    @categoryCore Types
    Result
    <void, 'UploadFileFailed'>;
    declare const
    const savePost: (id: string) => Result.Result<void, "PostCreateFailed">
    savePost
    : (
    id: string
    id
    : string) =>
    import Result
    Result
    .
    type Result<T, E> = Result.Success<T> | Result.Failure<E>

    A union type representing either a success or a failure.

    @typeParamT - The type of the Success value.@typeParamE - The type of the Failure value.@example
    import { Result } from '@praha/byethrow';
    
    const doSomething = (): Result.Result<number, string> => {
      return Math.random() > 0.5
        ? { type: 'Success', value: 10 }
        : { type: 'Failure', error: 'Oops' };
    };
    @categoryCore Types
    Result
    <void, 'PostCreateFailed'>;
    declare const
    const deleteFile: (path: string) => Result.Result<void, "DeleteFileFailed">
    deleteFile
    : (
    path: string
    path
    : string) =>
    import Result
    Result
    .
    type Result<T, E> = Result.Success<T> | Result.Failure<E>

    A union type representing either a success or a failure.

    @typeParamT - The type of the Success value.@typeParamE - The type of the Failure value.@example
    import { Result } from '@praha/byethrow';
    
    const doSomething = (): Result.Result<number, string> => {
      return Math.random() > 0.5
        ? { type: 'Success', value: 10 }
        : { type: 'Failure', error: 'Oops' };
    };
    @categoryCore Types
    Result
    <void, 'DeleteFileFailed'>;
    const
    const createPost: (id: string, path: string, content: string) => Result.Result<void, "UploadFileFailed" | "PostCreateFailed" | "DeleteFileFailed">
    createPost
    = (
    id: string
    id
    : string,
    path: string
    path
    : string,
    content: string
    content
    : string) =>
    import Result
    Result
    .
    const pipe: <Result.Result<void, "UploadFileFailed">, Result.Result<void, "UploadFileFailed" | "PostCreateFailed">, Result.Result<void, "UploadFileFailed" | "PostCreateFailed" | "DeleteFileFailed">>(a: Result.Result<void, "UploadFileFailed">, ab: (a: Result.Result<void, "UploadFileFailed">) => Result.Result<void, "UploadFileFailed" | "PostCreateFailed">, bc: (b: Result.Result<void, "UploadFileFailed" | "PostCreateFailed">) => Result.Result<void, "UploadFileFailed" | "PostCreateFailed" | "DeleteFileFailed">) => Result.Result<...> (+25 overloads)
    pipe
    (
    const uploadFile: (path: string, content: string) => Result.Result<void, "UploadFileFailed">
    uploadFile
    (`/posts/${
    id: string
    id
    }`,
    content: string
    content
    ),
    import Result
    Result
    .
    const andThen: <Result.Result<void, "UploadFileFailed">, Result.Result<void, "PostCreateFailed">>(fn: (a: void) => Result.Result<void, "PostCreateFailed">) => (result: Result.Result<void, "UploadFileFailed">) => Result.Result<void, "UploadFileFailed" | "PostCreateFailed"> (+1 overload)
    andThen
    (() =>
    const savePost: (id: string) => Result.Result<void, "PostCreateFailed">
    savePost
    (
    id: string
    id
    )),
    import Result
    Result
    .
    const orThrough: <Result.Result<void, "UploadFileFailed" | "PostCreateFailed">, Result.Result<void, "DeleteFileFailed">>(fn: (a: "UploadFileFailed" | "PostCreateFailed") => Result.Result<void, "DeleteFileFailed">) => (result: Result.Result<void, "UploadFileFailed" | "PostCreateFailed">) => Result.Result<void, "UploadFileFailed" | "PostCreateFailed" | "DeleteFileFailed"> (+1 overload)
    orThrough
    (() =>
    const deleteFile: (path: string) => Result.Result<void, "DeleteFileFailed">
    deleteFile
    (`/posts/${
    id: string
    id
    }`)),
    ); // createPost が失敗すると、クリーンアップのために deleteFile が呼ばれる // しかし元の PostCreateFailed が返される

    リファレンス

    関数目的
    andThrough(fn)元の値を保持しながらバリデーションを実行する
    orThrough(fn)元のエラーを保持しながら回復を試みる