• English
  • Mapping Results

    The map and mapError functions allow you to transform the values inside a Result without changing its type (Success or Failure).

    map - Transforming Success Values

    The map function transforms the success value of a Result. If the Result is a Failure, it passes through unchanged.

    Basic Usage

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<number, never>
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<2, never>, Result.Result<number, never>>(a: Result.Result<2, never>, ab: (a: Result.Result<2, never>) => Result.Result<number, never>) => Result.Result<number, never> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const succeed: <2>(value: 2) => Result.Result<2, never> (+1 overload)
    succeed
    (2),
    import Result
    Result
    .
    const map: <Result.Result<2, never>, number>(fn: (a: 2) => number) => (result: Result.Result<2, never>) => Result.Result<number, never> (+1 overload)
    map
    ((
    value: 2
    value
    ) =>
    value: 2
    value
    * 10),
    ); // { type: 'Success', value: 20 }

    When the Result is a Failure

    If the input is a Failure, map does nothing and returns the Failure as-is:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<number, "error">
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<never, "error">, Result.Result<number, "error">>(a: Result.Result<never, "error">, ab: (a: Result.Result<never, "error">) => Result.Result<number, "error">) => Result.Result<number, "error"> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const fail: <"error">(error: "error") => Result.Result<never, "error"> (+1 overload)
    fail
    ('error'),
    import Result
    Result
    .
    const map: <Result.Result<never, "error">, number>(fn: (a: never) => number) => (result: Result.Result<never, "error">) => Result.Result<number, "error"> (+1 overload)
    map
    ((
    value: never
    value
    ) =>
    value: never
    value
    * 10),
    ); // { type: 'Failure', error: 'error' }

    Example: Formatting Data for Display

    A common use case is transforming raw data into a display-friendly format:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    type
    type ProductRow = {
        id: number;
        name: string;
        priceInCents: number;
    }
    ProductRow
    = {
    id: number
    id
    : number;
    name: string
    name
    : string;
    priceInCents: number
    priceInCents
    : number;
    }; type
    type ProductView = {
        id: string;
        name: string;
        price: string;
    }
    ProductView
    = {
    id: string
    id
    : string;
    name: string
    name
    : string;
    price: string
    price
    : string;
    }; const
    const formatPrice: (cents: number) => string
    formatPrice
    = (
    cents: number
    cents
    : number): string => `$${(
    cents: number
    cents
    / 100).
    Number.toFixed(fractionDigits?: number): string

    Returns a string representing a number in fixed-point notation.

    @paramfractionDigits Number of digits after the decimal point. Must be in the range 0 - 20, inclusive.
    toFixed
    (2)}`;
    const
    const toProductView: (product: ProductRow) => ProductView
    toProductView
    = (
    product: ProductRow
    product
    :
    type ProductRow = {
        id: number;
        name: string;
        priceInCents: number;
    }
    ProductRow
    ):
    type ProductView = {
        id: string;
        name: string;
        price: string;
    }
    ProductView
    => ({
    id: string
    id
    :
    var String: StringConstructor
    (value?: any) => string

    Allows manipulation and formatting of text strings and determination and location of substrings within strings.

    String
    (
    product: ProductRow
    product
    .
    id: number
    id
    ),
    name: string
    name
    :
    product: ProductRow
    product
    .
    name: string
    name
    ,
    price: string
    price
    :
    const formatPrice: (cents: number) => string
    formatPrice
    (
    product: ProductRow
    product
    .
    priceInCents: number
    priceInCents
    ),
    }); const
    const getProductForDisplay: (id: number) => Result.ResultAsync<ProductView, "NotFound">
    getProductForDisplay
    = (
    id: number
    id
    : number):
    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 ProductView = {
        id: string;
        name: string;
        price: string;
    }
    ProductView
    , 'NotFound'> => {
    return
    import Result
    Result
    .
    const pipe: <Result.ResultAsync<ProductRow, "NotFound">, Result.ResultAsync<ProductView, "NotFound">>(a: Result.ResultAsync<ProductRow, "NotFound">, ab: (a: Result.ResultAsync<ProductRow, "NotFound">) => Result.ResultAsync<ProductView, "NotFound">) => Result.ResultAsync<ProductView, "NotFound"> (+25 overloads)
    pipe
    (
    const fetchProduct: (id: number) => Result.ResultAsync<ProductRow, "NotFound">
    fetchProduct
    (
    id: number
    id
    ),
    import Result
    Result
    .
    const map: <Result.ResultAsync<ProductRow, "NotFound">, ProductView>(fn: (a: ProductRow) => ProductView) => (result: Result.ResultAsync<ProductRow, "NotFound">) => Result.ResultAsync<ProductView, "NotFound"> (+1 overload)
    map
    (
    const toProductView: (product: ProductRow) => ProductView
    toProductView
    ),
    ); }; // Transforms the raw product data into a UI-friendly format

    mapError - Transforming Error Values

    The mapError function transforms the error value of a Result. If the Result is a Success, it passes through unchanged.

    Basic Usage

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<never, Error>
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<never, "NotFound">, Result.Result<never, Error>>(a: Result.Result<never, "NotFound">, ab: (a: Result.Result<never, "NotFound">) => Result.Result<never, Error>) => Result.Result<never, Error> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const fail: <"NotFound">(error: "NotFound") => Result.Result<never, "NotFound"> (+1 overload)
    fail
    ('NotFound'),
    import Result
    Result
    .
    const mapError: <Result.Result<never, "NotFound">, Error>(fn: (a: "NotFound") => Error) => (result: Result.Result<never, "NotFound">) => Result.Result<never, Error> (+1 overload)
    mapError
    ((
    error: "NotFound"
    error
    ) => new
    var Error: ErrorConstructor
    new (message?: string, options?: ErrorOptions) => Error (+1 overload)
    Error
    (
    error: "NotFound"
    error
    )),
    ); // { type: 'Failure', error: Error('NotFound') }

    When the Result is a Success

    If the input is a Success, mapError does nothing and returns the Success as-is:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const result: Result.Result<123, Error>
    result
    =
    import Result
    Result
    .
    const pipe: <Result.Result<123, never>, Result.Result<123, Error>>(a: Result.Result<123, never>, ab: (a: Result.Result<123, never>) => Result.Result<123, Error>) => Result.Result<123, Error> (+25 overloads)
    pipe
    (
    import Result
    Result
    .
    const succeed: <123>(value: 123) => Result.Result<123, never> (+1 overload)
    succeed
    (123),
    import Result
    Result
    .
    const mapError: <Result.Result<123, never>, Error>(fn: (a: never) => Error) => (result: Result.Result<123, never>) => Result.Result<123, Error> (+1 overload)
    mapError
    ((
    error: never
    error
    ) => new
    var Error: ErrorConstructor
    new (message?: string, options?: ErrorOptions) => Error (+1 overload)
    Error
    (
    error: never
    error
    )),
    ); // { type: 'Success', value: 123 }

    Example: Converting Internal Errors to HTTP Responses

    A common use case is converting domain-specific errors into standardized HTTP error responses:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    type
    type DomainError = {
        type: "NotFound";
        resource: string;
    } | {
        type: "ValidationError";
        field: string;
        message: string;
    } | {
        type: "Unauthorized";
    }
    DomainError
    =
    | {
    type: "NotFound"
    type
    : 'NotFound';
    resource: string
    resource
    : string }
    | {
    type: "ValidationError"
    type
    : 'ValidationError';
    field: string
    field
    : string;
    message: string
    message
    : string }
    | {
    type: "Unauthorized"
    type
    : 'Unauthorized' };
    type
    type HttpError = {
        status: number;
        body: {
            error: string;
            details?: string;
        };
    }
    HttpError
    = {
    status: number
    status
    : number;
    body: {
        error: string;
        details?: string;
    }
    body
    : {
    error: string
    error
    : string;
    details?: string | undefined
    details
    ?: string };
    }; const
    const toHttpError: (error: DomainError) => HttpError
    toHttpError
    = (
    error: DomainError
    error
    :
    type DomainError = {
        type: "NotFound";
        resource: string;
    } | {
        type: "ValidationError";
        field: string;
        message: string;
    } | {
        type: "Unauthorized";
    }
    DomainError
    ):
    type HttpError = {
        status: number;
        body: {
            error: string;
            details?: string;
        };
    }
    HttpError
    => {
    switch (
    error: DomainError
    error
    .
    type: "NotFound" | "ValidationError" | "Unauthorized"
    type
    ) {
    case 'NotFound': return {
    status: number
    status
    : 404,
    body: {
        error: string;
        details?: string;
    }
    body
    : {
    error: string
    error
    : 'Not Found',
    details?: string | undefined
    details
    : `${
    error: {
        type: "NotFound";
        resource: string;
    }
    error
    .
    resource: string
    resource
    } was not found` },
    }; case 'ValidationError': return {
    status: number
    status
    : 400,
    body: {
        error: string;
        details?: string;
    }
    body
    : {
    error: string
    error
    : 'Bad Request',
    details?: string | undefined
    details
    : `${
    error: {
        type: "ValidationError";
        field: string;
        message: string;
    }
    error
    .
    field: string
    field
    }: ${
    error: {
        type: "ValidationError";
        field: string;
        message: string;
    }
    error
    .
    message: string
    message
    }` },
    }; case 'Unauthorized': return {
    status: number
    status
    : 401,
    body: {
        error: string;
        details?: string;
    }
    body
    : {
    error: string
    error
    : 'Unauthorized' },
    }; } }; const
    const handleRequest: () => Result.ResultAsync<{
        data: string;
    }, HttpError>
    handleRequest
    = ():
    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
    <{
    data: string
    data
    : string },
    type HttpError = {
        status: number;
        body: {
            error: string;
            details?: string;
        };
    }
    HttpError
    > => {
    return
    import Result
    Result
    .
    const pipe: <Result.ResultAsync<{
        data: string;
    }, DomainError>, Result.ResultAsync<{
        data: string;
    }, HttpError>>(a: Result.ResultAsync<{
        data: string;
    }, DomainError>, ab: (a: Result.ResultAsync<{
        data: string;
    }, DomainError>) => Result.ResultAsync<{
        data: string;
    }, HttpError>) => Result.ResultAsync<{
        data: string;
    }, HttpError> (+25 overloads)
    pipe
    (
    const processRequest: () => Result.ResultAsync<{
        data: string;
    }, DomainError>
    processRequest
    (),
    import Result
    Result
    .
    const mapError: <Result.ResultAsync<{
        data: string;
    }, DomainError>, HttpError>(fn: (a: DomainError) => HttpError) => (result: Result.ResultAsync<{
        data: string;
    }, DomainError>) => Result.ResultAsync<{
        data: string;
    }, HttpError> (+1 overload)
    mapError
    (
    const toHttpError: (error: DomainError) => HttpError
    toHttpError
    ),
    ); }; // Converts domain errors into HTTP-appropriate error responses

    Combining map and mapError

    You can use both map and mapError in the same pipeline to transform both success and error values.

    Suppose you have a function that fetches a user from the database. The raw data may need formatting for the UI, and internal error codes need to be converted into user-friendly messages:

    import { 
    import Result
    Result
    } from '@praha/byethrow';
    const
    const toView: (row: UserRow) => UserView
    toView
    = (
    row: UserRow
    row
    :
    type UserRow = {
        id: number;
        first_name: string;
        last_name: string;
        created_at: string;
    }
    UserRow
    ):
    type UserView = {
        id: string;
        fullName: string;
        memberSince: string;
    }
    UserView
    => ({
    id: string
    id
    :
    var String: StringConstructor
    (value?: any) => string

    Allows manipulation and formatting of text strings and determination and location of substrings within strings.

    String
    (
    row: UserRow
    row
    .
    id: number
    id
    ),
    fullName: string
    fullName
    : `${
    row: UserRow
    row
    .
    first_name: string
    first_name
    } ${
    row: UserRow
    row
    .
    last_name: string
    last_name
    }`,
    memberSince: string
    memberSince
    : new
    var Date: DateConstructor
    new (value: number | string | Date) => Date (+4 overloads)
    Date
    (
    row: UserRow
    row
    .
    created_at: string
    created_at
    ).
    Date.toLocaleDateString(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string (+2 overloads)

    Converts a date to a string by using the current or specified locale.

    @paramlocales A locale string, array of locale strings, Intl.Locale object, or array of Intl.Locale objects that contain one or more language or locale tags. If you include more than one locale string, list them in descending order of priority so that the first entry is the preferred locale. If you omit this parameter, the default locale of the JavaScript runtime is used.@paramoptions An object that contains one or more properties that specify comparison options.
    toLocaleDateString
    (),
    }); const
    const toHttpError: (error: DatabaseError) => HttpError
    toHttpError
    = (
    error: DatabaseError
    error
    :
    type DatabaseError = "RECORD_NOT_FOUND" | "CONNECTION_FAILED" | "TIMEOUT"
    DatabaseError
    ):
    type HttpError = {
        status: number;
        body: {
            error: string;
            details?: string;
        };
    }
    HttpError
    => {
    switch (
    error: DatabaseError
    error
    ) {
    case 'RECORD_NOT_FOUND': return {
    status: number
    status
    : 404,
    body: {
        error: string;
        details?: string;
    }
    body
    : {
    error: string
    error
    : 'User Not Found',
    details?: string | undefined
    details
    : 'The requested user does not exist.',
    }, }; case 'CONNECTION_FAILED': case 'TIMEOUT': return {
    status: number
    status
    : 503,
    body: {
        error: string;
        details?: string;
    }
    body
    : {
    error: string
    error
    : 'Service Unavailable',
    details?: string | undefined
    details
    : 'Please try again later.',
    }, }; } }; const
    const getUserForView: (id: number) => Result.ResultAsync<UserView, HttpError>
    getUserForView
    = (
    id: number
    id
    : number):
    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 UserView = {
        id: string;
        fullName: string;
        memberSince: string;
    }
    UserView
    ,
    type HttpError = {
        status: number;
        body: {
            error: string;
            details?: string;
        };
    }
    HttpError
    > => {
    return
    import Result
    Result
    .
    const pipe: <Result.ResultAsync<UserRow, DatabaseError>, Result.ResultAsync<UserView, DatabaseError>, Result.ResultAsync<UserView, HttpError>>(a: Result.ResultAsync<UserRow, DatabaseError>, ab: (a: Result.ResultAsync<UserRow, DatabaseError>) => Result.ResultAsync<UserView, DatabaseError>, bc: (b: Result.ResultAsync<UserView, DatabaseError>) => Result.ResultAsync<...>) => Result.ResultAsync<...> (+25 overloads)
    pipe
    (
    const fetchUser: (id: number) => Result.ResultAsync<UserRow, DatabaseError>
    fetchUser
    (
    id: number
    id
    ),
    import Result
    Result
    .
    const map: <Result.ResultAsync<UserRow, DatabaseError>, UserView>(fn: (a: UserRow) => UserView) => (result: Result.ResultAsync<UserRow, DatabaseError>) => Result.ResultAsync<UserView, DatabaseError> (+1 overload)
    map
    (
    const toView: (row: UserRow) => UserView
    toView
    ),
    import Result
    Result
    .
    const mapError: <Result.ResultAsync<UserView, DatabaseError>, HttpError>(fn: (a: DatabaseError) => HttpError) => (result: Result.ResultAsync<UserView, DatabaseError>) => Result.ResultAsync<UserView, HttpError> (+1 overload)
    mapError
    (
    const toHttpError: (error: DatabaseError) => HttpError
    toHttpError
    ),
    ); }

    References

    FunctionPurpose
    map(fn)Transform the success value of a Result
    mapError(fn)Transform the error value of a Result