This repository demonstrates an experimental approach to handling try-catch blocks in TypeScript with enhanced type safety and flexibility. This pattern allows developers to explicitly define the types of errors that can be thrown while maintaining compatibility with traditional try-catch usage.
-
Full TypeScript Flexibility:
- Use the
Throws
utility to define the types of errors a function might throw. - If type definitions are not needed, the function works like a traditional try-catch and returns a tuple
[data, error]
.
- Use the
-
Explicit Error Types:
- For functions throwing multiple errors (e.g.,
CustomError
,Error
), useThrows
to explicitly declare them.
- For functions throwing multiple errors (e.g.,
-
Ease of Use:
- Handle returned tuples with an
if
statement to separate success from failure cases.
- Handle returned tuples with an
-
Duplicate Definitions:
- Errors need to be defined twice: once for throwing them and once in the return type. This is a design choice to ensure type safety, but it does not affect runtime behavior.
import { tryCatch, type Throws } from "./lib/try-catch";
class CustomError extends Error {}
function iMightFail(): string & Throws<CustomError> {
const random = Math.random();
if (random > 0.2) {
return "success";
} else if (random > 0.5) {
throw new CustomError();
}
throw new Error();
}
const [data, error] = tryCatch(() => iMightFail());
if (error1) {
console.log("i Might fail failed", error.message);
// ^? Error | CustomError
} else {
console.log("i succeeded", data);
// ^? string
}
function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function iMightFailAsync(): Promise<string & Throws<CustomError>> {
await sleep(200);
const random = Math.random();
if (random > 0.2) {
return "success";
} else if (random > 0.5) {
throw new CustomError();
}
throw new Error();
}
const [data, error] = await tryCatch(() => iMightFailAsync());
if (error2) {
console.log("i Might fail async failed", error.message);
// ^? Error | CustomError
} else {
console.log("i Might fail async succeeded", data);
// ^? string
}
function iMightFailOrNot() {
return "success"
}
const [data3, error3] = tryCatch(iMightFailOrNot);
if (error3) {
console.log("i Might fail or not failed", error3.message)
// ^? Error
} else {
console.log("i Might fail or not succeeded", data3)
// ^? string
}