2

I want to declare a const variable, initialize it inside a try block, and then use it outside of that try block. For example:

const result;

try {
    result = getResult();
} catch (error) {
    report(error);
    return;
}

use(result);

Or asynchronously:

const result;

try {
    result = await fetchResult();
} catch (error) {
    report(error);
    return;
}

use(result);

What I don't want:

  • Use let because that allows overwriting the result later on.
  • Move this to a separate function because I only want this logic to be accessible inside the given scope.

I'm seeing this pattern a lot in my code, so is there any way to do this using a modular TypeScript solution?

The following questions are similar, but don't provide a reusable type-safe solution:

Duncan Lukkenaer
  • 12,050
  • 13
  • 64
  • 97
  • If an error is thrown, the code below the `catch` is never used. Why not just put the subsequent code *inside* the `try`? – crashmstr Jan 06 '21 at 17:08
  • 1
    @crashmstr Because the code below the `catch` could also throw, and that might require different error handling. So putting everything inside the same `try` block could lead to unexpected behaviour. – Duncan Lukkenaer Jan 06 '21 at 17:54

1 Answers1

0

Synchronous solution

Use the following type-safe utility function:

function tryGet<T>(getter: () => T): {
    success: true;
    value: T;
} | {
    success: false;
    error: Error;
} {
    try {
        return {
            success: true,
            value: getter(),
        };
    } catch (error) {
        return {
            success: false,
            error: error as Error,
        };
    }
}

Usage:

import { report, use } from './imagination';

const result = tryGet(getValue);

if (!result.success) {
    report(result.error);
    return;
}

use(result.value);

Asynchronous solution

export default async function tryGetAsync<T>(
    getter: () => Promise<T>
): Promise<{
    success: true;
    result: T;
} | {
    success: false;
    error: Error;
}> {
    try {
        return {
            success: true,
            result: await getter(),
        };
    } catch (error) {
        return {
            success: false,
            error: error as Error,
        };
    }
}

Usage:

import { report, use } from './imagination';

const result = await tryGetAsync(fetchValue);

if (!result.success) {
    report(result.error);
    return;
}

use(result.value);
Duncan Lukkenaer
  • 12,050
  • 13
  • 64
  • 97