tryThis
A safe wrapper that catches errors from synchronous functions, async functions, and raw promises, returning a Go-style [error, result] tuple instead of throwing. Never write a try/catch block again.
Quick Start
Wrap any operation in Aura.tryThis() and destructure the result. If the operation succeeds, error is null. If it fails, result is null and error is an Error instance.
// Sync const [err, data] = Aura.tryThis(() => JSON.parse(rawString)); // Async const [err, users] = await Aura.tryThis(() => fetch('/api/users').then(r => r.json()) ); // Direct promise const [err, res] = await Aura.tryThis(fetch('/api/users'));
Signature
| Param | Type | Description |
|---|---|---|
| fnOrPromise | (() => T | Promise<T>) | Promise<T> | A sync function, an async function, or a Promise to wrap. |
Return Value
| Scenario | Return Type | Value |
|---|---|---|
| Sync success | [null, T] | Synchronous tuple with the result. |
| Sync failure | [Error, null] | Synchronous tuple with the caught error. |
| Async success | Promise<[null, T]> | Resolves with the result. |
| Async failure | Promise<[Error, null]> | Resolves (not rejects) with the error. |
Non-Error throws are automatically wrapped via new Error(String(thrown)), so the first element is always an Error instance or null.
The Tuple Pattern
The [error, result] tuple eliminates the need for try/catch blocks and makes error handling explicit at the call site. It is inspired by Go's multiple return values.
// Before — nested try/catch let config; try { config = JSON.parse(raw); } catch (e) { config = defaultConfig; } // After — flat and readable const [err, config] = Aura.tryThis(() => JSON.parse(raw)); if (err) config = defaultConfig;
Key rules:
- On success:
[null, value]— error is alwaysnull. - On failure:
[Error, null]— result is alwaysnull. - The function never throws. Async variants never reject.
Sync Functions
When you pass a function that returns a non-Promise value, tryThis returns a tuple synchronously — no await needed.
// Success const [err, num] = Aura.tryThis(() => parseInt('42', 10)); console.log(err); // null console.log(num); // 42 // Failure const [err, val] = Aura.tryThis(() => { throw new Error('boom'); }); console.log(err.message); // 'boom' console.log(val); // null
Async Functions
When the function returns a Promise (or is declared async), tryThis returns a Promise that resolves to the tuple. Use await to unwrap it.
const [err, users] = await Aura.tryThis(async () => { const res = await fetch('/api/users'); if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); }); if (err) { Aura.log.error('Failed to load users', err); } else { renderUsers(users); }
Direct Promises
You can also pass a Promise directly instead of wrapping it in a function. This is handy when you already have a Promise reference.
const promise = fetch('/api/config').then(r => r.json()); // Pass the promise directly const [err, config] = await Aura.tryThis(promise); if (err) { console.log('Using defaults', err.message); }
Recipe: JSON Parsing
Safely parse JSON without try/catch. Perfect for user input, localStorage, or WebSocket messages.
function safeParse(raw, fallback = null) { const [err, data] = Aura.tryThis(() => JSON.parse(raw)); return err ? fallback : data; } // Usage const settings = safeParse(localStorage.getItem('settings'), {}); const message = safeParse(wsEvent.data, { type: 'unknown' });
Recipe: API Calls
Combine tryThis with fetch for clean, flat async error handling.
async function getUser(id) { const [fetchErr, res] = await Aura.tryThis( fetch(`/api/users/${id}`) ); if (fetchErr) return { error: 'Network failure' }; if (!res.ok) return { error: `HTTP ${res.status}` }; const [parseErr, user] = await Aura.tryThis(res.json()); if (parseErr) return { error: 'Invalid JSON' }; return { data: user }; }
Recipe: File Reading
Read files via the File API without nested callbacks or try/catch.
async function readFile(file) { const [err, text] = await Aura.tryThis( new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result); reader.onerror = () => reject(reader.error); reader.readAsText(file); }) ); if (err) { console.error('Could not read file:', err.message); return null; } return text; }
Recipe: Chaining with Logger
Pair tryThis with Aura.log for structured error reporting without cluttering your business logic.
const api = Aura.log.tag('API'); async function loadDashboard() { const [err, data] = await Aura.tryThis(async () => { const res = await fetch('/api/dashboard'); if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); }); if (err) { api.error('Dashboard load failed', err); showFallbackUI(); return; } api.info('Dashboard loaded', { widgets: data.widgets.length }); renderDashboard(data); } // Sync + Logger const [parseErr, config] = Aura.tryThis(() => JSON.parse(localStorage.getItem('config')) ); if (parseErr) { Aura.log.warn('Config parse failed, using defaults', parseErr); } // Export errors for debugging const errorLog = Aura.log.export('error'); console.log(errorLog);