@pencroff-lab/kore 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/src/types/err.d.ts +1116 -0
- package/dist/cjs/src/types/err.d.ts.map +1 -0
- package/dist/cjs/src/types/err.js +1324 -0
- package/dist/cjs/src/types/err.js.map +1 -0
- package/dist/cjs/src/types/index.d.ts +3 -0
- package/dist/cjs/src/types/index.d.ts.map +1 -0
- package/dist/cjs/src/types/index.js +19 -0
- package/dist/cjs/src/types/index.js.map +1 -0
- package/dist/cjs/src/types/outcome.d.ts +1002 -0
- package/dist/cjs/src/types/outcome.d.ts.map +1 -0
- package/dist/cjs/src/types/outcome.js +958 -0
- package/dist/cjs/src/types/outcome.js.map +1 -0
- package/dist/cjs/src/utils/format_dt.d.ts +9 -0
- package/dist/cjs/src/utils/format_dt.d.ts.map +1 -0
- package/dist/cjs/src/utils/format_dt.js +29 -0
- package/dist/cjs/src/utils/format_dt.js.map +1 -0
- package/dist/cjs/src/utils/index.d.ts +2 -0
- package/dist/cjs/src/utils/index.d.ts.map +1 -0
- package/dist/cjs/src/utils/index.js +18 -0
- package/dist/cjs/src/utils/index.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/src/types/err.d.ts +1116 -0
- package/dist/esm/src/types/err.d.ts.map +1 -0
- package/dist/esm/src/types/err.js +1320 -0
- package/dist/esm/src/types/err.js.map +1 -0
- package/dist/esm/src/types/index.d.ts +3 -0
- package/dist/esm/src/types/index.d.ts.map +1 -0
- package/dist/esm/src/types/index.js +3 -0
- package/dist/esm/src/types/index.js.map +1 -0
- package/dist/esm/src/types/outcome.d.ts +1002 -0
- package/dist/esm/src/types/outcome.d.ts.map +1 -0
- package/dist/esm/src/types/outcome.js +954 -0
- package/dist/esm/src/types/outcome.js.map +1 -0
- package/dist/esm/src/utils/format_dt.d.ts +9 -0
- package/dist/esm/src/utils/format_dt.d.ts.map +1 -0
- package/dist/esm/src/utils/format_dt.js +26 -0
- package/dist/esm/src/utils/format_dt.js.map +1 -0
- package/dist/esm/src/utils/index.d.ts +2 -0
- package/dist/esm/src/utils/index.d.ts.map +1 -0
- package/dist/esm/src/utils/index.js +2 -0
- package/dist/esm/src/utils/index.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,1002 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview
|
|
3
|
+
* Monadic container for handling success and error states using tuple-first API design.
|
|
4
|
+
*
|
|
5
|
+
* This module provides the `Outcome<T>` class and related types for implementing
|
|
6
|
+
* type-safe error handling without exceptions. All operations favor immutability.
|
|
7
|
+
*
|
|
8
|
+
* @example Basic usage
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { Outcome } from './outcome';
|
|
11
|
+
*
|
|
12
|
+
* const [val, err] = Outcome.from(() => [42, null]).toTuple();
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @example Migration from throwing functions
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Before (throwing):
|
|
18
|
+
* function getUser(id: string): User {
|
|
19
|
+
* const user = db.find(id);
|
|
20
|
+
* if (!user) throw new Error("Not found");
|
|
21
|
+
* return user;
|
|
22
|
+
* }
|
|
23
|
+
* try {
|
|
24
|
+
* const user = getUser("123");
|
|
25
|
+
* console.log(user.name);
|
|
26
|
+
* } catch (e) {
|
|
27
|
+
* console.error(e.message);
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* // After (Outcome):
|
|
31
|
+
* function getUser(id: string): Outcome<User> {
|
|
32
|
+
* return Outcome.from(() => {
|
|
33
|
+
* const user = db.find(id);
|
|
34
|
+
* if (!user) return Err.from("Not found", "NOT_FOUND");
|
|
35
|
+
* return [user, null];
|
|
36
|
+
* });
|
|
37
|
+
* }
|
|
38
|
+
* const [user, err] = getUser("123").toTuple();
|
|
39
|
+
* if (err) {
|
|
40
|
+
* console.error(err.message);
|
|
41
|
+
* return;
|
|
42
|
+
* }
|
|
43
|
+
* console.log(user.name);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
import { Err, type ErrCode, type ErrOptions } from "./err";
|
|
47
|
+
/**
|
|
48
|
+
* Direct return types for errors or void success.
|
|
49
|
+
* - `null`: void success (function completed, no value to return)
|
|
50
|
+
* - `Err`: error (shorthand for `[null, Err]`)
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* function saveConfig(config: Config): NullErr {
|
|
55
|
+
* if (!config.valid) return Err.from('Invalid config');
|
|
56
|
+
* fs.writeFileSync('config.json', JSON.stringify(config));
|
|
57
|
+
* return null; // void success
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export type NullErr = null | Err;
|
|
62
|
+
/**
|
|
63
|
+
* Tuple-based result with positional semantics.
|
|
64
|
+
* - `[T, null]`: success with value
|
|
65
|
+
* - `[null, Err]`: error
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* function divide(a: number, b: number): ResultTuple<number> {
|
|
70
|
+
* if (b === 0) return [null, Err.from('Division by zero')];
|
|
71
|
+
* return [a / b, null];
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* const [result, err] = divide(10, 2);
|
|
75
|
+
* if (err) console.error(err.message);
|
|
76
|
+
* else console.log(result); // 5
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export type ResultTuple<T> = [T, null] | [null, Err];
|
|
80
|
+
/**
|
|
81
|
+
* Combined callback return type for `Outcome.from()` and `Outcome.fromAsync()`.
|
|
82
|
+
* Supports all patterns:
|
|
83
|
+
* - `[T, null]`: success with value (tuple)
|
|
84
|
+
* - `[null, Err]`: error (tuple)
|
|
85
|
+
* - `null`: void success
|
|
86
|
+
* - `Err`: error (shorthand)
|
|
87
|
+
*
|
|
88
|
+
* Discrimination order: `Err.isErr()` → `=== null` → destructure tuple
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* Outcome.from(() => {
|
|
93
|
+
* if (badInput) return Err.from('Bad input'); // Err shorthand
|
|
94
|
+
* if (noResult) return null; // void success
|
|
95
|
+
* if (hasError) return [null, Err.from('Error')]; // tuple error
|
|
96
|
+
* return [value, null]; // tuple success
|
|
97
|
+
* });
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export type CallbackReturn<T> = ResultTuple<T> | NullErr;
|
|
101
|
+
/**
|
|
102
|
+
* Synchronous pipe function type.
|
|
103
|
+
* Receives a ResultTuple and returns a CallbackReturn.
|
|
104
|
+
*
|
|
105
|
+
* @typeParam In - Input value type
|
|
106
|
+
* @typeParam Out - Output value type
|
|
107
|
+
*/
|
|
108
|
+
export type PipeFn<In, Out> = (tuple: ResultTuple<In>) => CallbackReturn<Out>;
|
|
109
|
+
/**
|
|
110
|
+
* Asynchronous pipe function type.
|
|
111
|
+
* Receives a ResultTuple and returns a Promise of CallbackReturn.
|
|
112
|
+
*
|
|
113
|
+
* @typeParam In - Input value type
|
|
114
|
+
* @typeParam Out - Output value type
|
|
115
|
+
*/
|
|
116
|
+
export type PipeFnAsync<In, Out> = (tuple: ResultTuple<In>) => Promise<CallbackReturn<Out>>;
|
|
117
|
+
/**
|
|
118
|
+
* A monadic container for handling success and error states.
|
|
119
|
+
*
|
|
120
|
+
* `Outcome<T>` provides a type-safe way to handle operations that can fail,
|
|
121
|
+
* using tuples as the primary interface. All instances are immutable.
|
|
122
|
+
*
|
|
123
|
+
* ## Core Patterns
|
|
124
|
+
*
|
|
125
|
+
* - **Construction**: Use static methods `ok()`, `err()`, `from()`, `fromAsync()`
|
|
126
|
+
* - **Inspection**: Use `isOk`, `isErr`, `value`, `error` properties
|
|
127
|
+
* - **Transformation**: Use `map()`, `mapErr()` for chained operations
|
|
128
|
+
* - **Extraction**: Use `toTuple()` for final value extraction
|
|
129
|
+
*
|
|
130
|
+
* @example Basic usage
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const outcome = Outcome.from(() => {
|
|
133
|
+
* if (Math.random() > 0.5) return [42, null];
|
|
134
|
+
* return Err.from('Bad luck');
|
|
135
|
+
* });
|
|
136
|
+
*
|
|
137
|
+
* const [value, err] = outcome.toTuple();
|
|
138
|
+
* if (err) {
|
|
139
|
+
* console.error('Failed:', err.message);
|
|
140
|
+
* } else {
|
|
141
|
+
* console.log('Success:', value);
|
|
142
|
+
* }
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* @example Chaining transformations
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const result = Outcome.ok(5)
|
|
148
|
+
* .map(n => [n * 2, null])
|
|
149
|
+
* .map(n => [n.toString(), null])
|
|
150
|
+
* .toTuple();
|
|
151
|
+
* // result: ['10', null]
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @typeParam T - The type of the success value
|
|
155
|
+
*/
|
|
156
|
+
export declare class Outcome<T> {
|
|
157
|
+
/**
|
|
158
|
+
* Discriminator property for type narrowing.
|
|
159
|
+
* `true` for success outcomes, `false` for error outcomes.
|
|
160
|
+
*/
|
|
161
|
+
readonly isOk: boolean;
|
|
162
|
+
/** Internal tuple storage */
|
|
163
|
+
private readonly _tuple;
|
|
164
|
+
/**
|
|
165
|
+
* Private constructor - use static factory methods.
|
|
166
|
+
* @internal
|
|
167
|
+
*/
|
|
168
|
+
private constructor();
|
|
169
|
+
/**
|
|
170
|
+
* Process a CallbackReturn value into an Outcome.
|
|
171
|
+
* Handles discrimination: Err → null (void) → tuple destructure.
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
174
|
+
private static _processCallbackReturn;
|
|
175
|
+
/**
|
|
176
|
+
* Create a success Outcome with the given value.
|
|
177
|
+
*
|
|
178
|
+
* @param value - The success value
|
|
179
|
+
* @returns Outcome containing the success value
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* const outcome = Outcome.ok(42);
|
|
184
|
+
* console.log(outcome.isOk); // true
|
|
185
|
+
* console.log(outcome.value); // 42
|
|
186
|
+
*
|
|
187
|
+
* const [val, err] = outcome.toTuple();
|
|
188
|
+
* // val: 42, err: null
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
static ok<T>(value: T): Outcome<T>;
|
|
192
|
+
/**
|
|
193
|
+
* Create an error Outcome from an existing Err.
|
|
194
|
+
*
|
|
195
|
+
* @param error - The Err instance
|
|
196
|
+
* @returns Outcome in error state
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```typescript
|
|
200
|
+
* const err = Err.from('Something failed');
|
|
201
|
+
* const outcome = Outcome.err(err);
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
static err(error: Err): Outcome<never>;
|
|
205
|
+
/**
|
|
206
|
+
* Create an error Outcome from a message with optional code.
|
|
207
|
+
*
|
|
208
|
+
* @param message - Error message
|
|
209
|
+
* @param code - Optional error code
|
|
210
|
+
* @returns Outcome in error state
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* const outcome = Outcome.err('Not found', 'NOT_FOUND');
|
|
215
|
+
* const [, err] = outcome.toTuple();
|
|
216
|
+
* console.log(err?.code); // 'NOT_FOUND'
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
static err(message: string, code?: ErrCode): Outcome<never>;
|
|
220
|
+
/**
|
|
221
|
+
* Create an error Outcome from a message with options.
|
|
222
|
+
*
|
|
223
|
+
* @param message - Error message
|
|
224
|
+
* @param options - Error options (code, metadata)
|
|
225
|
+
* @returns Outcome in error state
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```typescript
|
|
229
|
+
* const outcome = Outcome.err('Timeout', {
|
|
230
|
+
* code: 'TIMEOUT',
|
|
231
|
+
* metadata: { durationMs: 5000 }
|
|
232
|
+
* });
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
static err(message: string, options: ErrOptions): Outcome<never>;
|
|
236
|
+
/**
|
|
237
|
+
* Create an error Outcome by wrapping another error.
|
|
238
|
+
*
|
|
239
|
+
* @param message - Context message
|
|
240
|
+
* @param error - Original error to wrap
|
|
241
|
+
* @param options - Optional additional options
|
|
242
|
+
* @returns Outcome in error state with wrapped cause
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* try {
|
|
247
|
+
* JSON.parse(invalid);
|
|
248
|
+
* } catch (e) {
|
|
249
|
+
* return Outcome.err('Parse failed', e as Error, { code: 'PARSE_ERROR' });
|
|
250
|
+
* }
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
static err(message: string, error: Err | Error, options?: ErrOptions): Outcome<never>;
|
|
254
|
+
/**
|
|
255
|
+
* Create a success Outcome with null value (void success).
|
|
256
|
+
*
|
|
257
|
+
* Use for operations that succeed but have no meaningful return value.
|
|
258
|
+
*
|
|
259
|
+
* @returns Outcome<null> representing void success
|
|
260
|
+
*
|
|
261
|
+
* @remarks
|
|
262
|
+
* Returns `Outcome<null>` (not `Outcome<undefined>` or `Outcome<void>`).
|
|
263
|
+
* This is intentional for consistency with the tuple pattern where `null`
|
|
264
|
+
* indicates absence of error in `[value, null]`.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```typescript
|
|
268
|
+
* function logMessage(msg: string): Outcome<null> {
|
|
269
|
+
* console.log(msg);
|
|
270
|
+
* return Outcome.unit();
|
|
271
|
+
* }
|
|
272
|
+
*
|
|
273
|
+
* const outcome = logMessage('Hello');
|
|
274
|
+
* console.log(outcome.isOk); // true
|
|
275
|
+
* console.log(outcome.value); // null
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
static unit(): Outcome<null>;
|
|
279
|
+
/**
|
|
280
|
+
* Create an Outcome from a callback that returns `CallbackReturn<T>`.
|
|
281
|
+
*
|
|
282
|
+
* The callback can return:
|
|
283
|
+
* - `[value, null]` - success with value
|
|
284
|
+
* - `[null, Err]` - error as tuple
|
|
285
|
+
* - `null` - void success
|
|
286
|
+
* - `Err` - error directly
|
|
287
|
+
*
|
|
288
|
+
* If the callback throws, the exception is caught and wrapped in an error Outcome.
|
|
289
|
+
*
|
|
290
|
+
* @param fn - Callback returning CallbackReturn<T>
|
|
291
|
+
* @returns Outcome<T>
|
|
292
|
+
*
|
|
293
|
+
* @see {@link fromAsync} for the async version
|
|
294
|
+
*
|
|
295
|
+
* @example Success with value
|
|
296
|
+
* ```typescript
|
|
297
|
+
* const outcome = Outcome.from(() => {
|
|
298
|
+
* return [42, null];
|
|
299
|
+
* });
|
|
300
|
+
* console.log(outcome.value); // 42
|
|
301
|
+
* ```
|
|
302
|
+
*
|
|
303
|
+
* @example Error shorthand
|
|
304
|
+
* ```typescript
|
|
305
|
+
* const outcome = Outcome.from(() => {
|
|
306
|
+
* if (invalid) return Err.from('Invalid input');
|
|
307
|
+
* return [result, null];
|
|
308
|
+
* });
|
|
309
|
+
* ```
|
|
310
|
+
*
|
|
311
|
+
* @example Catching throws from external libraries
|
|
312
|
+
* ```typescript
|
|
313
|
+
* const outcome = Outcome.from(() => {
|
|
314
|
+
* const data = JSON.parse(untrustedInput); // may throw
|
|
315
|
+
* return [data, null];
|
|
316
|
+
* });
|
|
317
|
+
* // If JSON.parse throws, outcome.isErr === true
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
static from<T>(fn: () => CallbackReturn<T>): Outcome<T>;
|
|
321
|
+
/**
|
|
322
|
+
* Create an Outcome from an async callback that returns `Promise<CallbackReturn<T>>`.
|
|
323
|
+
*
|
|
324
|
+
* Async version of `from()` with identical semantics.
|
|
325
|
+
*
|
|
326
|
+
* @param fn - Async callback returning Promise<CallbackReturn<T>>
|
|
327
|
+
* @returns Promise<Outcome<T>>
|
|
328
|
+
*
|
|
329
|
+
* @see {@link from} for the synchronous version
|
|
330
|
+
*
|
|
331
|
+
* @example Async operation
|
|
332
|
+
* ```typescript
|
|
333
|
+
* const outcome = await Outcome.fromAsync(async () => {
|
|
334
|
+
* const response = await fetch('/api/data');
|
|
335
|
+
* if (!response.ok) {
|
|
336
|
+
* return Err.from('Request failed', { code: 'HTTP_ERROR' });
|
|
337
|
+
* }
|
|
338
|
+
* const data = await response.json();
|
|
339
|
+
* return [data, null];
|
|
340
|
+
* });
|
|
341
|
+
* ```
|
|
342
|
+
*
|
|
343
|
+
* @example With error aggregation
|
|
344
|
+
* ```typescript
|
|
345
|
+
* const outcome = await Outcome.fromAsync(async () => {
|
|
346
|
+
* let errors = Err.aggregate('Batch failed');
|
|
347
|
+
*
|
|
348
|
+
* const [a, errA] = await taskA().toTuple();
|
|
349
|
+
* if (errA) errors = errors.add(errA);
|
|
350
|
+
*
|
|
351
|
+
* const [b, errB] = await taskB().toTuple();
|
|
352
|
+
* if (errB) errors = errors.add(errB);
|
|
353
|
+
*
|
|
354
|
+
* if (errors.count > 0) return errors;
|
|
355
|
+
* return [{ a, b }, null];
|
|
356
|
+
* });
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
static fromAsync<T>(fn: () => Promise<CallbackReturn<T>>): Promise<Outcome<T>>;
|
|
360
|
+
/**
|
|
361
|
+
* Create an Outcome from an existing ResultTuple.
|
|
362
|
+
*
|
|
363
|
+
* Useful for deserializing Outcomes or converting from external tuple sources.
|
|
364
|
+
*
|
|
365
|
+
* @param tuple - A ResultTuple<T>
|
|
366
|
+
* @returns Outcome<T>
|
|
367
|
+
*
|
|
368
|
+
* @see {@link toTuple} for extracting the tuple from an Outcome
|
|
369
|
+
*
|
|
370
|
+
* @example Deserializing from JSON
|
|
371
|
+
* ```typescript
|
|
372
|
+
* const json = '["hello", null]';
|
|
373
|
+
* const tuple = JSON.parse(json) as ResultTuple<string>;
|
|
374
|
+
* const outcome = Outcome.fromTuple(tuple);
|
|
375
|
+
* console.log(outcome.value); // 'hello'
|
|
376
|
+
* ```
|
|
377
|
+
*
|
|
378
|
+
* @example Round-trip serialization
|
|
379
|
+
* ```typescript
|
|
380
|
+
* const original = Outcome.ok(42);
|
|
381
|
+
* const json = JSON.stringify(original.toJSON());
|
|
382
|
+
* const restored = Outcome.fromTuple(JSON.parse(json));
|
|
383
|
+
* console.log(restored.value); // 42
|
|
384
|
+
* ```
|
|
385
|
+
*/
|
|
386
|
+
static fromTuple<T>(tuple: ResultTuple<T>): Outcome<T>;
|
|
387
|
+
/**
|
|
388
|
+
* Create an Outcome from a JSON tuple produced by `toJSON()`.
|
|
389
|
+
*
|
|
390
|
+
* Accepts `[value, null]` for success or `[null, errJSON]` for errors.
|
|
391
|
+
* Errors are rehydrated with `Err.fromJSON()`.
|
|
392
|
+
*
|
|
393
|
+
* @param payload - JSON tuple from `Outcome.toJSON()`
|
|
394
|
+
* @returns Outcome<T>
|
|
395
|
+
*
|
|
396
|
+
* @see {@link toJSON} for serializing an Outcome to JSON
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* ```typescript
|
|
400
|
+
* const json = JSON.stringify(outcome.toJSON());
|
|
401
|
+
* const restored = Outcome.fromJSON(JSON.parse(json));
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
static fromJSON<T>(payload: [T, null] | [null, ReturnType<Err["toJSON"]>]): Outcome<T>;
|
|
405
|
+
/**
|
|
406
|
+
* Combines multiple Outcomes, succeeding if all succeed with an array of values.
|
|
407
|
+
* If any Outcome fails, returns an Err containing all failures aggregated via Err.aggregate().
|
|
408
|
+
*
|
|
409
|
+
* This is useful for validation scenarios where you need to collect all errors.
|
|
410
|
+
*
|
|
411
|
+
* For empty arrays, returns `Outcome.ok([])` (vacuous truth).
|
|
412
|
+
*
|
|
413
|
+
* @param outcomes - Array of Outcomes to combine
|
|
414
|
+
* @returns Outcome containing array of all success values, or aggregate error
|
|
415
|
+
*
|
|
416
|
+
* @remarks
|
|
417
|
+
* Time complexity: O(n) where n is the number of outcomes.
|
|
418
|
+
* All outcomes are evaluated (non-short-circuiting) to collect all errors.
|
|
419
|
+
*
|
|
420
|
+
* @example All succeed
|
|
421
|
+
* ```typescript
|
|
422
|
+
* const outcomes = [Outcome.ok(1), Outcome.ok(2), Outcome.ok(3)];
|
|
423
|
+
* const combined = Outcome.all(outcomes);
|
|
424
|
+
* console.log(combined.value); // [1, 2, 3]
|
|
425
|
+
* ```
|
|
426
|
+
*
|
|
427
|
+
* @example One fails
|
|
428
|
+
* ```typescript
|
|
429
|
+
* const outcomes = [
|
|
430
|
+
* Outcome.ok(1),
|
|
431
|
+
* Outcome.err('Failed'),
|
|
432
|
+
* Outcome.ok(3)
|
|
433
|
+
* ];
|
|
434
|
+
* const combined = Outcome.all(outcomes);
|
|
435
|
+
* console.log(combined.isErr); // true
|
|
436
|
+
* console.log(combined.error?.message); // 'Failed'
|
|
437
|
+
* ```
|
|
438
|
+
*
|
|
439
|
+
* @example Many fails
|
|
440
|
+
* ```typescript
|
|
441
|
+
* const mixed = [
|
|
442
|
+
* Outcome.ok(1),
|
|
443
|
+
* Outcome.err("Error A"),
|
|
444
|
+
* Outcome.err("Error B")
|
|
445
|
+
* ];
|
|
446
|
+
* const failed = Outcome.all(mixed);
|
|
447
|
+
* console.log(failed.isErr); // true
|
|
448
|
+
* // Error contains both "Error A" and "Error B"
|
|
449
|
+
* ```
|
|
450
|
+
*
|
|
451
|
+
* @example Empty array
|
|
452
|
+
* ```typescript
|
|
453
|
+
* const combined = Outcome.all([]);
|
|
454
|
+
* console.log(combined.value); // []
|
|
455
|
+
* ```
|
|
456
|
+
*/
|
|
457
|
+
static all<T>(outcomes: Outcome<T>[]): Outcome<T[]>;
|
|
458
|
+
/**
|
|
459
|
+
* Return the first successful Outcome from an array.
|
|
460
|
+
*
|
|
461
|
+
* Returns the first success encountered.
|
|
462
|
+
* Returns an aggregate error if ALL outcomes fail.
|
|
463
|
+
*
|
|
464
|
+
* For empty arrays, returns an error (no value to return).
|
|
465
|
+
*
|
|
466
|
+
* @param outcomes - Array of Outcomes to check
|
|
467
|
+
* @returns First successful Outcome, or aggregate of all errors
|
|
468
|
+
*
|
|
469
|
+
* @remarks
|
|
470
|
+
* Time complexity: O(n) worst case, but short-circuits on first success.
|
|
471
|
+
* Best case: O(1) if first outcome is successful.
|
|
472
|
+
*
|
|
473
|
+
* @example First success wins
|
|
474
|
+
* ```typescript
|
|
475
|
+
* const outcomes = [
|
|
476
|
+
* Outcome.err('First failed'),
|
|
477
|
+
* Outcome.ok(42),
|
|
478
|
+
* Outcome.ok(100)
|
|
479
|
+
* ];
|
|
480
|
+
* const result = Outcome.any(outcomes);
|
|
481
|
+
* console.log(result.value); // 42
|
|
482
|
+
* ```
|
|
483
|
+
*
|
|
484
|
+
* @example All fail
|
|
485
|
+
* ```typescript
|
|
486
|
+
* const outcomes = [
|
|
487
|
+
* Outcome.err('Error 1'),
|
|
488
|
+
* Outcome.err('Error 2')
|
|
489
|
+
* ];
|
|
490
|
+
* const result = Outcome.any(outcomes);
|
|
491
|
+
* console.log(result.isErr); // true
|
|
492
|
+
* console.log(result.error?.isAggregate); // true
|
|
493
|
+
* ```
|
|
494
|
+
*
|
|
495
|
+
* @example Empty array
|
|
496
|
+
* ```typescript
|
|
497
|
+
* const result = Outcome.any([]);
|
|
498
|
+
* console.log(result.isErr); // true
|
|
499
|
+
* console.log(result.error?.message); // 'No outcomes provided'
|
|
500
|
+
* ```
|
|
501
|
+
*/
|
|
502
|
+
static any<T>(outcomes: Outcome<T>[]): Outcome<T>;
|
|
503
|
+
/**
|
|
504
|
+
* Whether this Outcome is in error state.
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* ```typescript
|
|
508
|
+
* const success = Outcome.ok(42);
|
|
509
|
+
* const failure = Outcome.err('Failed');
|
|
510
|
+
*
|
|
511
|
+
* console.log(success.isErr); // false
|
|
512
|
+
* console.log(failure.isErr); // true
|
|
513
|
+
* ```
|
|
514
|
+
*/
|
|
515
|
+
get isErr(): boolean;
|
|
516
|
+
/**
|
|
517
|
+
* The success value, or null if in error state.
|
|
518
|
+
*
|
|
519
|
+
* @example
|
|
520
|
+
* ```typescript
|
|
521
|
+
* const success = Outcome.ok(42);
|
|
522
|
+
* const failure = Outcome.err('Failed');
|
|
523
|
+
*
|
|
524
|
+
* console.log(success.value); // 42
|
|
525
|
+
* console.log(failure.value); // null
|
|
526
|
+
* ```
|
|
527
|
+
*/
|
|
528
|
+
get value(): T | null;
|
|
529
|
+
/**
|
|
530
|
+
* The error, or null if in success state.
|
|
531
|
+
*
|
|
532
|
+
* @example
|
|
533
|
+
* ```typescript
|
|
534
|
+
* const success = Outcome.ok(42);
|
|
535
|
+
* const failure = Outcome.err('Failed');
|
|
536
|
+
*
|
|
537
|
+
* console.log(success.error); // null
|
|
538
|
+
* console.log(failure.error?.message); // 'Failed'
|
|
539
|
+
* ```
|
|
540
|
+
*/
|
|
541
|
+
get error(): Err | null;
|
|
542
|
+
/**
|
|
543
|
+
* Transform the success value using a callback.
|
|
544
|
+
*
|
|
545
|
+
* Only called if this Outcome is successful. Errors pass through unchanged.
|
|
546
|
+
* The callback can return any `CallbackReturn<U>` pattern.
|
|
547
|
+
* If the callback throws, the exception is caught and wrapped.
|
|
548
|
+
*
|
|
549
|
+
* @param fn - Transformation function receiving the success value
|
|
550
|
+
* @returns New Outcome with transformed value or original/new error
|
|
551
|
+
*
|
|
552
|
+
* @see {@link mapAsync} for the async version
|
|
553
|
+
* @see {@link mapErr} for transforming or recovering from errors
|
|
554
|
+
*
|
|
555
|
+
* @example Simple transformation
|
|
556
|
+
* ```typescript
|
|
557
|
+
* const outcome = Outcome.ok(5)
|
|
558
|
+
* .map(n => [n * 2, null])
|
|
559
|
+
* .map(n => [n.toString(), null]);
|
|
560
|
+
*
|
|
561
|
+
* console.log(outcome.value); // '10'
|
|
562
|
+
* ```
|
|
563
|
+
*
|
|
564
|
+
* @example Transformation that can fail
|
|
565
|
+
* ```typescript
|
|
566
|
+
* const outcome = Outcome.ok('{"name":"John"}')
|
|
567
|
+
* .map(json => {
|
|
568
|
+
* try {
|
|
569
|
+
* return [JSON.parse(json), null];
|
|
570
|
+
* } catch {
|
|
571
|
+
* return Err.from('Invalid JSON');
|
|
572
|
+
* }
|
|
573
|
+
* });
|
|
574
|
+
* ```
|
|
575
|
+
*
|
|
576
|
+
* @example Error passes through
|
|
577
|
+
* ```typescript
|
|
578
|
+
* const outcome = Outcome.err('Original error')
|
|
579
|
+
* .map(v => [v * 2, null]); // Never called
|
|
580
|
+
*
|
|
581
|
+
* console.log(outcome.error?.message); // 'Original error'
|
|
582
|
+
* ```
|
|
583
|
+
*/
|
|
584
|
+
map<U>(fn: (value: T) => CallbackReturn<U>): Outcome<U>;
|
|
585
|
+
/**
|
|
586
|
+
* Async version of `map()`.
|
|
587
|
+
*
|
|
588
|
+
* @param fn - Async transformation function
|
|
589
|
+
* @returns Promise of new Outcome
|
|
590
|
+
*
|
|
591
|
+
* @see {@link map} for the synchronous version
|
|
592
|
+
*
|
|
593
|
+
* @example
|
|
594
|
+
* ```typescript
|
|
595
|
+
* const outcome = await Outcome.ok(userId)
|
|
596
|
+
* .mapAsync(async id => {
|
|
597
|
+
* const user = await fetchUser(id);
|
|
598
|
+
* return [user, null];
|
|
599
|
+
* });
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
mapAsync<U>(fn: (value: T) => Promise<CallbackReturn<U>>): Promise<Outcome<U>>;
|
|
603
|
+
/**
|
|
604
|
+
* Transform or recover from an error using a callback.
|
|
605
|
+
*
|
|
606
|
+
* Only called if this Outcome is in error state. Success passes through unchanged.
|
|
607
|
+
* The callback can return any `CallbackReturn<U>` pattern, allowing:
|
|
608
|
+
* - Recovery: return `[value, null]` to convert error to success
|
|
609
|
+
* - Transform: return `Err` or `[null, Err]` to change the error
|
|
610
|
+
*
|
|
611
|
+
* @param fn - Function receiving the error
|
|
612
|
+
* @returns New Outcome with transformed error or recovered value
|
|
613
|
+
*
|
|
614
|
+
* @see {@link mapErrAsync} for the async version
|
|
615
|
+
* @see {@link map} for transforming success values
|
|
616
|
+
*
|
|
617
|
+
* @example Recovery
|
|
618
|
+
* ```typescript
|
|
619
|
+
* const outcome = Outcome.err('Not found')
|
|
620
|
+
* .mapErr(err => {
|
|
621
|
+
* if (err.hasCode('NOT_FOUND')) {
|
|
622
|
+
* return [defaultValue, null]; // recover with default
|
|
623
|
+
* }
|
|
624
|
+
* return err; // pass through other errors
|
|
625
|
+
* });
|
|
626
|
+
* ```
|
|
627
|
+
*
|
|
628
|
+
* @example Error transformation
|
|
629
|
+
* ```typescript
|
|
630
|
+
* const outcome = Outcome.err('Low-level error')
|
|
631
|
+
* .mapErr(err => err.wrap('High-level context'));
|
|
632
|
+
* ```
|
|
633
|
+
*
|
|
634
|
+
* @example Logging and pass-through
|
|
635
|
+
* ```typescript
|
|
636
|
+
* const outcome = Outcome.err('Something failed')
|
|
637
|
+
* .mapErr(err => {
|
|
638
|
+
* console.error('Error occurred:', err.message);
|
|
639
|
+
* return err; // pass through unchanged
|
|
640
|
+
* });
|
|
641
|
+
* ```
|
|
642
|
+
*/
|
|
643
|
+
mapErr<U>(fn: (error: Err) => CallbackReturn<U>): Outcome<T | U>;
|
|
644
|
+
/**
|
|
645
|
+
* Async version of `mapErr()`.
|
|
646
|
+
*
|
|
647
|
+
* @param fn - Async function receiving the error
|
|
648
|
+
* @returns Promise of new Outcome
|
|
649
|
+
*
|
|
650
|
+
* @see {@link mapErr} for the synchronous version
|
|
651
|
+
*
|
|
652
|
+
* @example Async recovery with fallback fetch
|
|
653
|
+
* ```typescript
|
|
654
|
+
* const outcome = await Outcome.err('Primary failed')
|
|
655
|
+
* .mapErrAsync(async err => {
|
|
656
|
+
* const fallback = await fetchFromBackup();
|
|
657
|
+
* if (fallback) return [fallback, null];
|
|
658
|
+
* return err.wrap('Backup also failed');
|
|
659
|
+
* });
|
|
660
|
+
* ```
|
|
661
|
+
*/
|
|
662
|
+
mapErrAsync<U>(fn: (error: Err) => Promise<CallbackReturn<U>>): Promise<Outcome<T | U>>;
|
|
663
|
+
/**
|
|
664
|
+
* Execute a side effect with access to the full tuple.
|
|
665
|
+
*
|
|
666
|
+
* The callback receives the tuple `[value, error]` regardless of state.
|
|
667
|
+
* Returns `this` unchanged for chaining.
|
|
668
|
+
* If the callback throws, the exception is caught and the Outcome becomes an error.
|
|
669
|
+
*
|
|
670
|
+
* @param fn - Side effect function receiving the tuple
|
|
671
|
+
* @returns This Outcome (for chaining), or error Outcome if callback throws
|
|
672
|
+
*
|
|
673
|
+
* @see {@link effectAsync} for the async version
|
|
674
|
+
*
|
|
675
|
+
* @example Logging
|
|
676
|
+
* ```typescript
|
|
677
|
+
* const outcome = Outcome.ok(42)
|
|
678
|
+
* .effect(([val, err]) => {
|
|
679
|
+
* if (err) console.error('Failed:', err.message);
|
|
680
|
+
* else console.log('Success:', val);
|
|
681
|
+
* })
|
|
682
|
+
* .map(v => [v * 2, null]);
|
|
683
|
+
* ```
|
|
684
|
+
*
|
|
685
|
+
* @example Metrics
|
|
686
|
+
* ```typescript
|
|
687
|
+
* outcome.effect(([val, err]) => {
|
|
688
|
+
* metrics.record({
|
|
689
|
+
* success: !err,
|
|
690
|
+
* value: val,
|
|
691
|
+
* errorCode: err?.code
|
|
692
|
+
* });
|
|
693
|
+
* });
|
|
694
|
+
* ```
|
|
695
|
+
*/
|
|
696
|
+
effect(fn: (tuple: ResultTuple<T>) => void): Outcome<T>;
|
|
697
|
+
/**
|
|
698
|
+
* Async version of `effect()`.
|
|
699
|
+
*
|
|
700
|
+
* @param fn - Async side effect function
|
|
701
|
+
* @returns Promise of this Outcome
|
|
702
|
+
*
|
|
703
|
+
* @see {@link effect} for the synchronous version
|
|
704
|
+
*
|
|
705
|
+
* @example Async logging
|
|
706
|
+
* ```typescript
|
|
707
|
+
* const outcome = await Outcome.ok(data)
|
|
708
|
+
* .effectAsync(async ([val, err]) => {
|
|
709
|
+
* await logger.log({ value: val, error: err?.toJSON() });
|
|
710
|
+
* });
|
|
711
|
+
* ```
|
|
712
|
+
*/
|
|
713
|
+
effectAsync(fn: (tuple: ResultTuple<T>) => Promise<void>): Promise<Outcome<T>>;
|
|
714
|
+
/**
|
|
715
|
+
* Extract the success value, or use a fallback value on error.
|
|
716
|
+
*
|
|
717
|
+
* This is a terminal operation that exits the Outcome chain.
|
|
718
|
+
* Returns `T` directly, not wrapped in Outcome.
|
|
719
|
+
*
|
|
720
|
+
* @param fallback - The fallback value to use if in error state
|
|
721
|
+
* @returns The success value or the fallback
|
|
722
|
+
* @throws If the outcome is an error and computing fallback throws
|
|
723
|
+
*
|
|
724
|
+
* @see {@link either} for transforming both cases with custom logic
|
|
725
|
+
* @see {@link toTuple} for raw tuple extraction
|
|
726
|
+
*
|
|
727
|
+
* @example Static fallback
|
|
728
|
+
* ```typescript
|
|
729
|
+
* const count = parseNumber(input).defaultTo(0);
|
|
730
|
+
* // Returns parsed number or 0 on error
|
|
731
|
+
* ```
|
|
732
|
+
*
|
|
733
|
+
* @example With objects
|
|
734
|
+
* ```typescript
|
|
735
|
+
* const config = loadConfig().defaultTo({ port: 3000, host: 'localhost' });
|
|
736
|
+
* ```
|
|
737
|
+
*/
|
|
738
|
+
defaultTo(fallback: T): T;
|
|
739
|
+
/**
|
|
740
|
+
* Extract the success value, or compute a fallback from the error.
|
|
741
|
+
*
|
|
742
|
+
* This is a terminal operation that exits the Outcome chain.
|
|
743
|
+
* The handler receives the `Err` and can use it to compute the fallback.
|
|
744
|
+
*
|
|
745
|
+
* @param handler - Function to compute fallback from error
|
|
746
|
+
* @returns The success value or computed fallback
|
|
747
|
+
* @throws If the handler throws, the exception propagates to the caller
|
|
748
|
+
*
|
|
749
|
+
* @example Computed fallback
|
|
750
|
+
* ```typescript
|
|
751
|
+
* const name = fetchUser(id).defaultTo(err =>
|
|
752
|
+
* err.hasCode('NOT_FOUND') ? 'Guest' : 'Unknown'
|
|
753
|
+
* );
|
|
754
|
+
* ```
|
|
755
|
+
*
|
|
756
|
+
* @example Logging and fallback
|
|
757
|
+
* ```typescript
|
|
758
|
+
* const data = loadData().defaultTo(err => {
|
|
759
|
+
* console.error('Load failed:', err.message);
|
|
760
|
+
* return cachedData;
|
|
761
|
+
* });
|
|
762
|
+
* ```
|
|
763
|
+
*/
|
|
764
|
+
defaultTo(handler: (error: Err) => T): T;
|
|
765
|
+
/**
|
|
766
|
+
* Extract the success value, or use the provided fallback value.
|
|
767
|
+
*
|
|
768
|
+
* When T is a function type, use this overload with `asValue: true`
|
|
769
|
+
* to force treating the fallback as a static value rather than an error handler.
|
|
770
|
+
*
|
|
771
|
+
* @param fallback - The fallback value to use when error
|
|
772
|
+
* @param asValue - Must be `true` to use this overload
|
|
773
|
+
* @returns The success value or the fallback
|
|
774
|
+
*
|
|
775
|
+
* @example Function as a fallback value
|
|
776
|
+
* ```typescript
|
|
777
|
+
* const defaultHandler = () => console.log('default');
|
|
778
|
+
* const handler = getHandler().defaultTo(defaultHandler, true);
|
|
779
|
+
* ```
|
|
780
|
+
*/
|
|
781
|
+
defaultTo(fallback: T, asValue: true): T;
|
|
782
|
+
/**
|
|
783
|
+
* Transform the Outcome into a final value by handling both cases.
|
|
784
|
+
*
|
|
785
|
+
* This is a terminal operation that exits the Outcome chain, similar to
|
|
786
|
+
* `toTuple()` but with transformation logic applied.
|
|
787
|
+
*
|
|
788
|
+
* Each handler receives only its relevant type with full type safety:
|
|
789
|
+
* - `onOk` receives `T` (guaranteed non-null value)
|
|
790
|
+
* - `onErr` receives `Err` (guaranteed error)
|
|
791
|
+
*
|
|
792
|
+
* @param onOk - Function to transform success value into final result
|
|
793
|
+
* @param onErr - Function to transform error into final result
|
|
794
|
+
* @returns The transformed value (not wrapped in Outcome)
|
|
795
|
+
* @throws If either callback throws, the exception propagates to the caller
|
|
796
|
+
*
|
|
797
|
+
* @see {@link defaultTo} for simple value extraction with fallback
|
|
798
|
+
* @see {@link toTuple} for raw tuple extraction
|
|
799
|
+
* @see {@link toJSON} for JSON serialization
|
|
800
|
+
*
|
|
801
|
+
* @example Basic transformation
|
|
802
|
+
* ```typescript
|
|
803
|
+
* const message = fetchUser(id).either(
|
|
804
|
+
* user => `Welcome, ${user.name}!`,
|
|
805
|
+
* err => `Error: ${err.message}`
|
|
806
|
+
* );
|
|
807
|
+
* // message is string, not Outcome<string>
|
|
808
|
+
* ```
|
|
809
|
+
*
|
|
810
|
+
* @example HTTP response building
|
|
811
|
+
* ```typescript
|
|
812
|
+
* const response = processOrder(orderId).either(
|
|
813
|
+
* order => ({ status: 200, body: { id: order.id, total: order.total } }),
|
|
814
|
+
* err => ({
|
|
815
|
+
* status: err.hasCode('NOT_FOUND') ? 404 : 500,
|
|
816
|
+
* body: { error: err.message }
|
|
817
|
+
* })
|
|
818
|
+
* );
|
|
819
|
+
* ```
|
|
820
|
+
*
|
|
821
|
+
* @example Default value on error
|
|
822
|
+
* ```typescript
|
|
823
|
+
* const count = parseNumber(input).either(n => n, () => 0);
|
|
824
|
+
* ```
|
|
825
|
+
*
|
|
826
|
+
* @example Type transformation
|
|
827
|
+
* ```typescript
|
|
828
|
+
* const status: 'success' | 'error' = outcomeEntity.either(
|
|
829
|
+
* () => 'success',
|
|
830
|
+
* () => 'error'
|
|
831
|
+
* );
|
|
832
|
+
* ```
|
|
833
|
+
*/
|
|
834
|
+
either<U>(onOk: (value: T) => U, onErr: (error: Err) => U): U;
|
|
835
|
+
/**
|
|
836
|
+
* Chain synchronous transformations using tuple-based predicates.
|
|
837
|
+
*
|
|
838
|
+
* Each predicate receives `ResultTuple<T>` and returns `CallbackReturn<U>`.
|
|
839
|
+
* This allows handling both success and error cases at each step,
|
|
840
|
+
* enabling mid-chain recovery or conditional transformations.
|
|
841
|
+
*
|
|
842
|
+
* @see {@link pipeAsync} for async transformations
|
|
843
|
+
* @see {@link map} for simple success-only transformation
|
|
844
|
+
* @see {@link mapErr} for error-only transformation
|
|
845
|
+
*
|
|
846
|
+
* @example Basic pipeline
|
|
847
|
+
* ```typescript
|
|
848
|
+
* const result = Outcome.ok(rawInput).pipe(
|
|
849
|
+
* ([val, err]) => {
|
|
850
|
+
* if (err) return err;
|
|
851
|
+
* return [validate(val), null];
|
|
852
|
+
* },
|
|
853
|
+
* ([val, err]) => {
|
|
854
|
+
* if (err) return err;
|
|
855
|
+
* return [transform(val), null];
|
|
856
|
+
* }
|
|
857
|
+
* );
|
|
858
|
+
* ```
|
|
859
|
+
*
|
|
860
|
+
* @example Mid-chain recovery
|
|
861
|
+
* ```typescript
|
|
862
|
+
* const result = Outcome.ok(input).pipe(
|
|
863
|
+
* ([val, err]) => {
|
|
864
|
+
* if (err) return err;
|
|
865
|
+
* if (!val.isValid) return Err.from('Invalid', 'VALIDATION');
|
|
866
|
+
* return [val, null];
|
|
867
|
+
* },
|
|
868
|
+
* ([val, err]) => {
|
|
869
|
+
* // Recover from validation error
|
|
870
|
+
* if (err?.hasCode('VALIDATION')) {
|
|
871
|
+
* return [DEFAULT_VALUE, null];
|
|
872
|
+
* }
|
|
873
|
+
* if (err) return err;
|
|
874
|
+
* return [val.process(), null];
|
|
875
|
+
* }
|
|
876
|
+
* );
|
|
877
|
+
* ```
|
|
878
|
+
*/
|
|
879
|
+
pipe<A>(f1: PipeFn<T, A>): Outcome<A>;
|
|
880
|
+
pipe<A, B>(f1: PipeFn<T, A>, f2: PipeFn<A, B>): Outcome<B>;
|
|
881
|
+
pipe<A, B, C>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>): Outcome<C>;
|
|
882
|
+
pipe<A, B, C, D>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>): Outcome<D>;
|
|
883
|
+
pipe<A, B, C, D, E>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>): Outcome<E>;
|
|
884
|
+
pipe<A, B, C, D, E, F>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>): Outcome<F>;
|
|
885
|
+
pipe<A, B, C, D, E, F, G>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>, f7: PipeFn<F, G>): Outcome<G>;
|
|
886
|
+
pipe<A, B, C, D, E, F, G, H>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>, f7: PipeFn<F, G>, f8: PipeFn<G, H>): Outcome<H>;
|
|
887
|
+
pipe<A, B, C, D, E, F, G, H, I>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>, f7: PipeFn<F, G>, f8: PipeFn<G, H>, f9: PipeFn<H, I>): Outcome<I>;
|
|
888
|
+
pipe<A, B, C, D, E, F, G, H, I, J>(f1: PipeFn<T, A>, f2: PipeFn<A, B>, f3: PipeFn<B, C>, f4: PipeFn<C, D>, f5: PipeFn<D, E>, f6: PipeFn<E, F>, f7: PipeFn<F, G>, f8: PipeFn<G, H>, f9: PipeFn<H, I>, f10: PipeFn<I, J>): Outcome<J>;
|
|
889
|
+
/**
|
|
890
|
+
* Chain asynchronous transformations using tuple-based predicates.
|
|
891
|
+
*
|
|
892
|
+
* Each predicate receives `ResultTuple<T>` and returns `Promise<CallbackReturn<U>>`.
|
|
893
|
+
* Predicates are executed sequentially, each awaiting the previous result.
|
|
894
|
+
*
|
|
895
|
+
* @see {@link pipe} for synchronous transformations
|
|
896
|
+
* @see {@link mapAsync} for simple async success-only transformation
|
|
897
|
+
* @see {@link mapErrAsync} for async error-only transformation
|
|
898
|
+
*
|
|
899
|
+
* @example Async pipeline
|
|
900
|
+
* ```typescript
|
|
901
|
+
* const result = await Outcome.ok(userId).pipeAsync(
|
|
902
|
+
* async ([val, err]) => {
|
|
903
|
+
* if (err) return err;
|
|
904
|
+
* const user = await fetchUser(val);
|
|
905
|
+
* return [user, null];
|
|
906
|
+
* },
|
|
907
|
+
* async ([user, err]) => {
|
|
908
|
+
* if (err) return err;
|
|
909
|
+
* const profile = await fetchProfile(user.profileId);
|
|
910
|
+
* return [{ ...user, profile }, null];
|
|
911
|
+
* }
|
|
912
|
+
* );
|
|
913
|
+
* ```
|
|
914
|
+
*
|
|
915
|
+
* @example Async recovery
|
|
916
|
+
* ```typescript
|
|
917
|
+
* const result = await Outcome.ok(id).pipeAsync(
|
|
918
|
+
* async ([val, err]) => {
|
|
919
|
+
* if (err) return err;
|
|
920
|
+
* return await fetchFromPrimary(val);
|
|
921
|
+
* },
|
|
922
|
+
* async ([val, err]) => {
|
|
923
|
+
* // Fallback to secondary on error
|
|
924
|
+
* if (err) {
|
|
925
|
+
* return await fetchFromSecondary(id);
|
|
926
|
+
* }
|
|
927
|
+
* return [val, null];
|
|
928
|
+
* }
|
|
929
|
+
* );
|
|
930
|
+
* ```
|
|
931
|
+
*/
|
|
932
|
+
pipeAsync<A>(f1: PipeFnAsync<T, A>): Promise<Outcome<A>>;
|
|
933
|
+
pipeAsync<A, B>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>): Promise<Outcome<B>>;
|
|
934
|
+
pipeAsync<A, B, C>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>): Promise<Outcome<C>>;
|
|
935
|
+
pipeAsync<A, B, C, D>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>): Promise<Outcome<D>>;
|
|
936
|
+
pipeAsync<A, B, C, D, E>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>): Promise<Outcome<E>>;
|
|
937
|
+
pipeAsync<A, B, C, D, E, F>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>): Promise<Outcome<F>>;
|
|
938
|
+
pipeAsync<A, B, C, D, E, F, G>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>, f7: PipeFnAsync<F, G>): Promise<Outcome<G>>;
|
|
939
|
+
pipeAsync<A, B, C, D, E, F, G, H>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>, f7: PipeFnAsync<F, G>, f8: PipeFnAsync<G, H>): Promise<Outcome<H>>;
|
|
940
|
+
pipeAsync<A, B, C, D, E, F, G, H, I>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>, f7: PipeFnAsync<F, G>, f8: PipeFnAsync<G, H>, f9: PipeFnAsync<H, I>): Promise<Outcome<I>>;
|
|
941
|
+
pipeAsync<A, B, C, D, E, F, G, H, I, J>(f1: PipeFnAsync<T, A>, f2: PipeFnAsync<A, B>, f3: PipeFnAsync<B, C>, f4: PipeFnAsync<C, D>, f5: PipeFnAsync<D, E>, f6: PipeFnAsync<E, F>, f7: PipeFnAsync<F, G>, f8: PipeFnAsync<G, H>, f9: PipeFnAsync<H, I>, f10: PipeFnAsync<I, J>): Promise<Outcome<J>>;
|
|
942
|
+
/**
|
|
943
|
+
* Extract the internal tuple.
|
|
944
|
+
*
|
|
945
|
+
* Primary method for extracting values from an Outcome.
|
|
946
|
+
* Use destructuring for ergonomic access.
|
|
947
|
+
*
|
|
948
|
+
* @returns The internal ResultTuple<T>
|
|
949
|
+
*
|
|
950
|
+
* @see {@link fromTuple} for creating an Outcome from a tuple
|
|
951
|
+
*
|
|
952
|
+
* @example
|
|
953
|
+
* ```typescript
|
|
954
|
+
* const outcome = Outcome.ok(42);
|
|
955
|
+
* const [value, error] = outcome.toTuple();
|
|
956
|
+
*
|
|
957
|
+
* if (error) {
|
|
958
|
+
* console.error('Failed:', error.message);
|
|
959
|
+
* return;
|
|
960
|
+
* }
|
|
961
|
+
* console.log('Value:', value); // 42
|
|
962
|
+
* ```
|
|
963
|
+
*/
|
|
964
|
+
toTuple(): ResultTuple<T>;
|
|
965
|
+
/**
|
|
966
|
+
* Convert to JSON-serializable tuple.
|
|
967
|
+
*
|
|
968
|
+
* For success: returns `[value, null]`
|
|
969
|
+
* For error: returns `[null, errJSON]` where errJSON is from `Err.toJSON()`
|
|
970
|
+
*
|
|
971
|
+
* @returns JSON-serializable representation
|
|
972
|
+
*
|
|
973
|
+
* @see {@link fromJSON} for deserializing an Outcome from JSON
|
|
974
|
+
*
|
|
975
|
+
* @example
|
|
976
|
+
* ```typescript
|
|
977
|
+
* const outcome = Outcome.ok({ name: 'John' });
|
|
978
|
+
* const json = JSON.stringify(outcome.toJSON());
|
|
979
|
+
* // '[{"name":"John"},null]'
|
|
980
|
+
*
|
|
981
|
+
* // Deserialize
|
|
982
|
+
* const restored = Outcome.fromJSON(JSON.parse(json));
|
|
983
|
+
* ```
|
|
984
|
+
*/
|
|
985
|
+
toJSON(): [T, null] | [null, ReturnType<Err["toJSON"]>];
|
|
986
|
+
/**
|
|
987
|
+
* Convert to a human-readable string.
|
|
988
|
+
*
|
|
989
|
+
* @returns String representation
|
|
990
|
+
*
|
|
991
|
+
* @example
|
|
992
|
+
* ```typescript
|
|
993
|
+
* console.log(Outcome.ok(42).toString());
|
|
994
|
+
* // 'Outcome.ok(42)'
|
|
995
|
+
*
|
|
996
|
+
* console.log(Outcome.err('Failed').toString());
|
|
997
|
+
* // 'Outcome.err([ERROR] Failed)'
|
|
998
|
+
* ```
|
|
999
|
+
*/
|
|
1000
|
+
toString(): string;
|
|
1001
|
+
}
|
|
1002
|
+
//# sourceMappingURL=outcome.d.ts.map
|