UNPKG

@itsezz/try-catch

Version:

A TypeScript utility for elegant error handling with Result types

241 lines (171 loc) 6.66 kB
# @itsezz/try-catch <div align="center"> [![npm version](https://img.shields.io/npm/v/@itsezz/try-catch?color=2563eb&style=flat-square)](https://www.npmjs.com/package/@itsezz/try-catch) [![npm downloads](https://img.shields.io/npm/dm/@itsezz/try-catch?color=2563eb&style=flat-square)](https://www.npmjs.com/package/@itsezz/try-catch) [![license](https://img.shields.io/npm/l/@itsezz/try-catch?color=10b981&style=flat-square)](https://github.com/itsEzz/try-catch/blob/main/LICENSE) [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-3178c6?style=flat-square)](https://www.typescriptlang.org/) [![Bundle Size](https://img.shields.io/bundlephobia/min/@itsezz/try-catch?color=f59e0b&style=flat-square)](https://bundlephobia.com/package/@itsezz/try-catch) A lightweight TypeScript utility for elegant error handling using the **Result pattern**. Say goodbye to messy try/catch blocks and hello to type-safe, composable error management. </div> ## Why Result Pattern? - ✅ **Explicit errors** — every failure is a deliberate return value - ✅ **Full type safety** — TypeScript knows exactly what's possible - ✅ **Composable** — chain operations without nesting ## Installation ```bash # npm npm install @itsezz/try-catch # pnpm pnpm add @itsezz/try-catch # yarn yarn add @itsezz/try-catch ``` ## Quick Start ```typescript import { tryCatch, isSuccess } from '@itsezz/try-catch'; // Wrap any operation that might fail const result = tryCatch(() => JSON.parse(userInput)); // Handle both cases explicitly if (isSuccess(result)) { console.log('Parsed data:', result.data); // ✅ Fully typed! } else { console.error('Parse failed:', result.error); // ✅ Error is typed! } ``` ## The Result Type At the core is the `Result<T, E>` type — a discriminated union that represents either success or failure: ```typescript type Result<T, E = Error> = | { ok: true; data: T; error?: never } // Success case | { ok: false; data?: never; error: E }; // Failure case ``` The `ok` property acts as a discriminant, enabling perfect type narrowing. ## Usage ### Synchronous Functions ```typescript import { tryCatch, isSuccess } from '@itsezz/try-catch'; const result = tryCatch(() => { const data = fs.readFileSync('config.json', 'utf-8'); return JSON.parse(data); }); if (isSuccess(result)) { console.log(result.data); // TypeScript knows this is the read config file content } else { console.error(result.error.message); } ``` ### Asynchronous Operations ```typescript import { tryCatch, isError } from '@itsezz/try-catch'; const user = await tryCatch(fetch('/api/user').then(r => r.json())); if (isError(user)) { handleError(user.error); return; } console.log(user.data.name); // Fully typed! ``` ### Explicit Context Need to guarantee sync or async? Use the specific variants: ```typescript import { tryCatchSync, tryCatchAsync } from '@itsezz/try-catch'; // Always returns Result<T, E> (never a Promise) const syncResult = tryCatchSync(() => expensiveCalculation()); // Always returns Promise<Result<T, E>> const asyncResult = await tryCatchAsync(fetchUser(id)); ``` ## API Reference ### Core Functions | Function | Description | | ----------------- | ------------------------------------------------ | | `tryCatch() ` | Auto-detects sync/async and returns accordingly* | | `tryCatchSync()` | Guarantees synchronous `Result<T, E>` | | `tryCatchAsync()` | Guarantees `Promise<Result<T, E>>` | | `t()` | Short alias for `tryCatch` | | `tc()` | Short alias for `tryCatchSync` | | `tca()` | Short alias for `tryCatchAsync` | > \* `tryCatch` may not correctly infer if the result is `Promise<Result<T,E>>` or `Result<T,E>` in certain conditions and defaults to `Promise<Result<T,E>>` when unsure. Use explicit variants for guaranteed type safety. ### Type Guards ```typescript isSuccess(result) // Returns true if ok === true isError(result) // Returns true if ok === false ``` ### Transformation ```typescript // Transform success data, pass through errors map(result, (data) => data.toUpperCase()) // Chain another operation that might fail flatMap(result, (data) => tryCatchSync(() => validate(data))) ``` ### Combination ```typescript const results = await Promise.all([ tryCatchAsync(fetchUser(1)), tryCatchAsync(fetchUser(2)), tryCatchAsync(fetchUser(3)), ]); // Returns all data if all succeed, or first error if any fail const allUsers = all(results); ``` ### Error Handling ```typescript // Pattern matching match(result, { success: (data) => process(data), failure: (error) => logError(error), }); // Get data or default const value = unwrapOr(result, defaultValue); // Get data or compute from error const value = unwrapOrElse(result, (error) => computeFallback(error)); ``` ## Examples ### Custom Error Types ```typescript interface ApiError { code: number; message: string; } const result = tryCatchSync<User, ApiError>(() => { if (!user) throw { code: 404, message: 'User not found' }; return user; }); if (!result.ok) { // result.error is typed as ApiError console.log(result.error.code); // ✅ No type assertion needed! } ``` ### Functional Pipeline ```typescript import { tryCatchAsync, flatMap, map, all } from '@itsezz/try-catch'; const getUserWithPosts = async (userId: string) => { const userResult = await tryCatchAsync(fetchUser(userId)); return flatMap(userResult, async (user) => { const [postsResult, profileResult] = await all([ tryCatchAsync(fetchPosts(userId)), tryCatchAsync(fetchProfile(userId)), ]); if (!postsResult.ok) return postsResult; if (!profileResult.ok) return profileResult; return { ...user, posts: postsResult.data, profile: profileResult.data }; }); }; ``` ### Safe JSON Parsing ```typescript import { tryCatch } from '@itsezz/try-catch'; const safeJsonParse = <T>(json: string): T | null => { const result = tryCatch(() => JSON.parse(json) as T); return result.ok ? result.data : null; }; // Usage const config = safeJsonParse<Config>(rawJson); if (config) { // Use config... } ``` ## License MIT © [itsEzz](https://github.com/itsEzz) --- <div align="center"> **⭐ If you find this useful, consider starring the repo! ⭐** </div>