@kreisler/try-catch
Functional utilities for error handling that eliminate the need for verbose try-catch blocks. Provides composable, type-safe error handling patterns.
Installation
npm install @kreisler/try-catch
Functions
tryCatch
Synchronous error handling that returns a tuple with error and result.
fn
(...args: P) => D
required
The function to execute. Can be synchronous.
Arguments to pass to the function.
Returns a tuple where:
- On success:
[null, result] - error is null, result is the function return value
- On error:
[Error] - contains the caught error
tryCatchPromise
Asynchronous error handling for promises that returns a tuple with error and result.
fn
(...args: P) => Promise<D> | D
required
The function to execute. Can be asynchronous or synchronous.
Arguments to pass to the function.
return
Promise<[null, D] | [Error]>
Returns a promise that resolves to a tuple where:
- On success:
[null, result] - error is null, result is the function return value
- On error:
[Error] - contains the caught error
tryToCatch
Executes a function and catches errors, allowing recovery with an alternative value.
The function to attempt execution.
catchFunction
(ex: unknown) => TCatchResult
required
Function to execute if an error occurs. Receives the error and can return a fallback value.
return
TTryResult | TCatchResult
Returns either the result of tryFunction on success or the result of catchFunction on error.
tryFinally
Executes a function with guaranteed cleanup via a finally block.
Function to execute in the finally block, regardless of success or failure.
Returns the result of tryFunction if successful, or undefined if an error occurred.
tryCatchFinally
Executes a function with error recovery and guaranteed cleanup.
The function to attempt execution.
catchFunction
(ex: unknown) => TCatchResult
required
Function to execute if an error occurs.
Function to execute in the finally block.
return
TTryResult | TCatchResult
Returns either the result of tryFunction or catchFunction.
Type Definitions
type TtryCatchPromise = Promise<TtryCatch>
type TtryCatch = [error: Error | null | unknown, result?: any]
type Tfn = (...args: any[]) => any
type T = any
Usage Examples
tryCatch - Basic Usage
import { tryCatch } from '@kreisler/try-catch'
const [error, result] = tryCatch(() => {
return JSON.parse('{"valid": "json"}')
})
if (error) {
console.error('Parse failed:', error.message)
} else {
console.log('Parsed data:', result)
}
tryCatch - With Error
import { tryCatch } from '@kreisler/try-catch'
const [error, result] = tryCatch(() => {
throw new Error('Something went wrong')
})
if (error) {
console.error(error.message) // "Something went wrong"
} else {
console.log(result) // Won't execute
}
tryCatchPromise - Fetch API
import { tryCatchPromise } from '@kreisler/try-catch'
const [error, result] = await tryCatchPromise(
globalThis.fetch,
'https://jsonplaceholder.typicode.com/todos/1'
)
if (error) {
console.error('Fetch failed:', error.message)
} else {
const data = await result.json()
console.log(data)
}
tryCatchPromise - Async Function
import { tryCatchPromise } from '@kreisler/try-catch'
const fetchUser = async (id: number) => {
const response = await fetch(`/api/users/${id}`)
if (!response.ok) throw new Error('User not found')
return response.json()
}
const [error, user] = await tryCatchPromise(fetchUser, 123)
if (error) {
console.error('Failed to fetch user:', error.message)
} else {
console.log('User:', user)
}
tryToCatch - Fallback Value
import { tryToCatch } from '@kreisler/try-catch'
const result = tryToCatch(
() => {
return JSON.parse(invalidJson)
},
(error) => {
console.error('Parse failed, using default')
return { default: true }
}
)
console.log(result) // { default: true }
tryToCatch - Error Recovery
import { tryToCatch } from '@kreisler/try-catch'
const getUserName = (userId: number) => {
return tryToCatch(
() => {
const user = database.getUser(userId)
if (!user) throw new Error('User not found')
return user.name
},
(error) => {
return 'Anonymous'
}
)
}
console.log(getUserName(999)) // "Anonymous"
tryFinally - Resource Cleanup
import { tryFinally } from '@kreisler/try-catch'
const result = tryFinally(
() => {
console.log('Performing operation...')
return 'Success'
},
() => {
console.log('Cleanup complete')
}
)
// Logs:
// "Performing operation..."
// "Cleanup complete"
// Returns: "Success"
tryCatchFinally - Complete Error Handling
import { tryCatchFinally } from '@kreisler/try-catch'
const result = tryCatchFinally(
() => {
console.log('Attempting operation...')
throw new Error('Operation failed')
},
(ex) => {
console.error('Error caught:', ex.message)
return 'Fallback value'
},
() => {
console.log('Cleanup executed')
}
)
// Logs:
// "Attempting operation..."
// "Error caught: Operation failed"
// "Cleanup executed"
// Returns: "Fallback value"
File Processing Example
import { tryCatchFinally } from '@kreisler/try-catch'
import * as fs from 'fs'
const processFile = (filename: string) => {
let fileHandle: number | null = null
return tryCatchFinally(
() => {
fileHandle = fs.openSync(filename, 'r')
const content = fs.readFileSync(fileHandle, 'utf-8')
return JSON.parse(content)
},
(error) => {
console.error('Failed to process file:', error)
return null
},
() => {
if (fileHandle !== null) {
fs.closeSync(fileHandle)
console.log('File handle closed')
}
}
)
}
API Call with Tuple Pattern
import { tryCatchPromise } from '@kreisler/try-catch'
const apiCall = async (endpoint: string) => {
const [error, response] = await tryCatchPromise(fetch, endpoint)
if (error) {
return [error, null] as const
}
const [parseError, data] = await tryCatchPromise(() => response.json())
if (parseError) {
return [parseError, null] as const
}
return [null, data] as const
}
// Usage
const [error, data] = await apiCall('/api/users')
if (error) {
console.error('API call failed:', error.message)
} else {
console.log('Users:', data)
}
Database Transaction
import { tryCatchFinally } from '@kreisler/try-catch'
const updateUserWithTransaction = (userId: number, updates: object) => {
return tryCatchFinally(
() => {
db.beginTransaction()
const user = db.users.update(userId, updates)
db.commit()
return user
},
(error) => {
console.error('Transaction failed:', error)
db.rollback()
throw error
},
() => {
db.closeConnection()
}
)
}
Comparison with Traditional Try-Catch
Traditional Approach
let result
try {
result = await fetchData()
} catch (error) {
console.error(error)
result = null
}
With @kreisler/try-catch
const [error, result] = await tryCatchPromise(fetchData)
if (error) console.error(error)
Benefits
- Cleaner Code: Eliminates nested try-catch blocks
- Type Safety: Full TypeScript support with proper type inference
- Composability: Easy to chain and combine error handling patterns
- Explicit Error Handling: Forces you to handle errors explicitly
- Functional Style: Aligns with functional programming principles
- Tuple Pattern: Go-style error handling for JavaScript/TypeScript