Futurable.try()
Wraps any callback — synchronous, asynchronous, throwing or returning — into a Futurable.
Syntax
typescript
// With optional cancellation signal
Futurable.try<T>(func: () => T | PromiseLike<T> | FuturableLike<T>, signal?: AbortSignal): Futurable<Awaited<T>>
// With arguments forwarded to the callback (Promise.try-compatible)
Futurable.try<T, U extends unknown[]>(func: (...args: U) => T | PromiseLike<T> | FuturableLike<T>, ...args: U): Futurable<Awaited<T>>Parameters
func
A function of any kind. It may:
- Return a plain value synchronously
- Throw synchronously
- Return a
PromiseorFuturable - Be an
asyncfunction (which may throw or resolve)
signal (optional)
An AbortSignal to link cancellation of the returned Futurable to an external controller. If provided, it must be passed as the last argument. See the Notes section for the known limitation this introduces.
...args (optional)
Arguments forwarded to func. If the last argument is an AbortSignal, it is intercepted as a cancellation signal and not passed to func.
Comparison
| Approach | Catches sync throws? | Calls fn synchronously? |
|---|---|---|
Futurable.resolve(fn()) | ❌ | ✅ |
Futurable.resolve().then(fn) | ✅ | ❌ |
new Futurable(res => res(fn())) | ✅ | ✅ |
Futurable.try(fn) | ✅ | ✅ |
Notes
funcis called synchronously at the momentFuturable.try()is invoked- Synchronous
throwinsidefuncbecomes a rejected Futurable - Returning a rejected
Promisealso produces a rejected Futurable - The return type is always
Futurable<Awaited<T>>— nested Promises are unwrapped automatically - Cancellation via
signalworks as with any other Futurable, but must be passed as the last argument - Known limitation: if your callback intentionally expects an
AbortSignalas its last parameter, it will be intercepted as a cancellation signal and not forwarded tofunc. Close over the signal manually instead:
typescript
const mySignal = controller.signal;
// ❌ mySignal is intercepted, NOT passed to the callback
Futurable.try((signal) => myFn(signal), mySignal);
// ✅ correct approach
Futurable.try(() => myFn(mySignal));- This method mirrors the
Promise.try()TC39 proposal (Stage 4, ES2026)
Examples
Basic Usage
typescript
import { Futurable } from '@ndriadev/futurable';
// Works with sync functions
const a = await Futurable.try(() => 42);
// 42
// Works with async functions
const b = await Futurable.try(async () => {
const res = await fetch('/api/data');
return res.json();
});
// Catches synchronous throws
const c = await Futurable.try(() => {
throw new Error('oops');
}).catch(err => 'recovered');
// 'recovered'Unifying Sync and Async Callbacks
typescript
function execute(action: () => unknown) {
return Futurable.try(action)
.then(result => console.log('Result:', result))
.catch(error => console.error('Error:', error))
.finally(() => console.log('Done'));
}
execute(() => 'sync value');
execute(() => { throw new Error('sync error'); });
execute(async () => 'async value');
execute(async () => { throw new Error('async error'); });Safe JSON Parsing
typescript
const result = await Futurable.try(() => JSON.parse(rawInput))
.safe();
if (result.success) {
console.log('Parsed:', result.data);
} else {
console.error('Invalid JSON:', result.error);
}With Cancellation
typescript
const controller = new AbortController();
const futurable = Futurable.try(
() => fetch('/api/slow').then(r => r.json()),
controller.signal
);
// Cancel after 2 seconds
setTimeout(() => controller.abort(), 2000);
await futurable.catch(() => console.log('Cancelled or errored'));Chaining with Other Methods
typescript
const result = await Futurable.try(() => loadConfig())
.then(config => validateConfig(config))
.then(config => applyConfig(config))
.safe();
if (!result.success) {
console.error('Config error:', result.error);
}Notes
funcis called synchronously at the momentFuturable.try()is invoked- Synchronous
throwinsidefuncbecomes a rejected Futurable - Returning a rejected
Promisealso produces a rejected Futurable - Cancellation via
signalworks as with any other Futurable - This method mirrors the
Promise.try()TC39 proposal (Stage 4, ES2026)
See Also
- safe() — resolve to a result object instead of throwing
- futurizable() — convert an existing Promise into a Futurable
- FuturableTask.try() — lazy equivalent for FuturableTask
