Skip to content

Instantly share code, notes, and snippets.

@t3dotgg
Last active September 5, 2025 16:58
Show Gist options
  • Save t3dotgg/a486c4ae66d32bf17c09c73609dacc5b to your computer and use it in GitHub Desktop.
Save t3dotgg/a486c4ae66d32bf17c09c73609dacc5b to your computer and use it in GitHub Desktop.
Theo's preferred way of handling try/catch in TypeScript
// Types for the result object with discriminated union
type Success<T> = {
data: T;
error: null;
};
type Failure<E> = {
data: null;
error: E;
};
type Result<T, E = Error> = Success<T> | Failure<E>;
// Main wrapper function
export async function tryCatch<T, E = Error>(
promise: Promise<T>,
): Promise<Result<T, E>> {
try {
const data = await promise;
return { data, error: null };
} catch (error) {
return { data: null, error: error as E };
}
}
@H7ioo
Copy link

H7ioo commented Jun 17, 2025 via email

@lcdss
Copy link

lcdss commented Jun 17, 2025

I was getting an error inside of the tryCatch function. It was something like operation is not a function or something like that. So . execute solved it for me. Edit: - Though it is better to handle this in the tryCatch function. Edit 2: Drizzle has an interesting (at least to me) implementation where if you don’t await, it returns a builder. If you do await, it becomes a Promise. More info about Thenables (MDN) The issue was that I was calling operation(), which returned a builder, not a Promise. So if I’m not wrong, inside the tryCatch block, if I wrap the result with Promise.resolve, it should work. ts const query = new FakeQuery(['user1', 'user2']); // Treated like a builder console.log('Query object:', query); // Auto-executes on await const result = await query; console.log('Result:', result);

So it's related to the fixes @nazarEnzo applied a few comments above, where he passed the promises to Promise.resolve method. I still haven't used the tryCacth function with any prisma promise yet, but when I do, I'll come back here if any issue arises.

@nazarEnzo
Copy link

FYI: My initial answer code wasn't actually working properly for synchronous operations, because the return was always a Promise. Now this is fixed by using custom isPromise utility (to support non-native promises). Promise.resolve().then() can totally be replaced with .then()

/**
 * Checks if the value is a Promise
 * @param value - The value to check
 * @returns True if the value is a Promise, false otherwise
 */
export function isPromise<T = any>(value: unknown): value is Promise<T> {
    return (
        !!value &&
        (typeof value === 'object' || typeof value === 'function') &&
        typeof (value as any).then === 'function'
    );
}

// ----------------
// Test
// ----------------

import prismaClient from 'database/prismaClient';

const userPromise = prismaClient.user.findFirst();

console.log(
    userPromise instanceof Promise, // false
    isPromise(userPromise) // true
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment