@pvorona/failable 0.0.1 → 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/README.md +288 -9
- package/dist/index.js +67 -55
- package/dist/lib/failable.d.ts +30 -34
- package/dist/lib/failable.d.ts.map +1 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
A typed result type for expected failures. `Failable<T, E>` is a discriminated union of `Success<T>` and `Failure<E>`, with ergonomic accessors and structured-clone support.
|
|
4
4
|
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @pvorona/failable
|
|
9
|
+
```
|
|
10
|
+
|
|
5
11
|
## Usage
|
|
6
12
|
|
|
7
13
|
```ts
|
|
8
|
-
import {
|
|
14
|
+
import { createFailable } from '@pvorona/failable';
|
|
9
15
|
|
|
10
|
-
const result =
|
|
16
|
+
const result = createFailable(() => JSON.parse(text));
|
|
11
17
|
|
|
12
18
|
if (result.isSuccess) {
|
|
13
19
|
console.log(result.data);
|
|
@@ -19,21 +25,29 @@ if (result.isSuccess) {
|
|
|
19
25
|
### Factories
|
|
20
26
|
|
|
21
27
|
```ts
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
import { failure, success } from '@pvorona/failable';
|
|
29
|
+
|
|
30
|
+
const ok = success(42);
|
|
31
|
+
const err = failure(new Error('boom'));
|
|
24
32
|
```
|
|
25
33
|
|
|
26
34
|
### Fallbacks
|
|
27
35
|
|
|
28
36
|
```ts
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
import { failure } from '@pvorona/failable';
|
|
38
|
+
|
|
39
|
+
const err = failure(new Error('boom'));
|
|
40
|
+
|
|
41
|
+
const value = err.getOr('default'); // 'default'
|
|
42
|
+
const recovered = err.or('fallback'); // Success<'fallback'>
|
|
31
43
|
```
|
|
32
44
|
|
|
33
45
|
### Wrapping async work
|
|
34
46
|
|
|
35
47
|
```ts
|
|
36
|
-
|
|
48
|
+
import { createFailable } from '@pvorona/failable';
|
|
49
|
+
|
|
50
|
+
const result = await createFailable(fetch('/api'));
|
|
37
51
|
```
|
|
38
52
|
|
|
39
53
|
### Structured-clone transport
|
|
@@ -41,10 +55,275 @@ const result = await Failable.from(fetch('/api'));
|
|
|
41
55
|
`Failable` instances use Symbols and prototype methods that do not survive structured cloning (`postMessage`, `chrome.runtime.sendMessage`, etc.). Convert to a plain object first:
|
|
42
56
|
|
|
43
57
|
```ts
|
|
58
|
+
import { createFailable, toFailableLike } from '@pvorona/failable';
|
|
59
|
+
|
|
44
60
|
// sender
|
|
45
|
-
const wire =
|
|
61
|
+
const wire = toFailableLike(result);
|
|
46
62
|
postMessage(wire);
|
|
47
63
|
|
|
48
64
|
// receiver
|
|
49
|
-
const hydrated =
|
|
65
|
+
const hydrated = createFailable(wire);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## API
|
|
69
|
+
|
|
70
|
+
### `const enum FailableStatus`
|
|
71
|
+
|
|
72
|
+
The discriminant for `FailableLike` and `Failable` instances.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
export const enum FailableStatus {
|
|
76
|
+
Success = 'success',
|
|
77
|
+
Failure = 'failure',
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Example:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { FailableStatus, type FailableLike } from '@pvorona/failable';
|
|
85
|
+
|
|
86
|
+
const ok: FailableLike<number, string> = {
|
|
87
|
+
status: FailableStatus.Success,
|
|
88
|
+
data: 1,
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `type Failable<T, E>`
|
|
93
|
+
|
|
94
|
+
Alias for `Success<T> | Failure<E>`.
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import type { Failable } from '@pvorona/failable';
|
|
100
|
+
import { failure, success } from '@pvorona/failable';
|
|
101
|
+
|
|
102
|
+
export function parseIntSafe(input: string): Failable<number, Error> {
|
|
103
|
+
const n = Number(input);
|
|
104
|
+
if (!Number.isInteger(n)) return failure(new Error('Not an int'));
|
|
105
|
+
|
|
106
|
+
return success(n);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### `type Success<T>`
|
|
111
|
+
|
|
112
|
+
The success variant.
|
|
113
|
+
|
|
114
|
+
Key fields/methods:
|
|
115
|
+
|
|
116
|
+
- `status: 'success'`, `isSuccess: true`, `isError: false`
|
|
117
|
+
- `data: T`, `error: null`
|
|
118
|
+
- `or(value)` returns itself
|
|
119
|
+
- `getOr(_)` returns `data`
|
|
120
|
+
- `getOrThrow()` returns `data`
|
|
121
|
+
|
|
122
|
+
Example:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { success } from '@pvorona/failable';
|
|
126
|
+
|
|
127
|
+
const s = success(123);
|
|
128
|
+
s.getOr(0); // 123
|
|
129
|
+
s.or('x'); // Success<number>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `type Failure<E>`
|
|
133
|
+
|
|
134
|
+
The failure variant.
|
|
135
|
+
|
|
136
|
+
Key fields/methods:
|
|
137
|
+
|
|
138
|
+
- `status: 'failure'`, `isSuccess: false`, `isError: true`
|
|
139
|
+
- `error: E`, `data: null`
|
|
140
|
+
- `or(value)` converts to `Success<typeof value>`
|
|
141
|
+
- `getOr(fallback)` returns `fallback`
|
|
142
|
+
- `getOrThrow()` throws `error`
|
|
143
|
+
|
|
144
|
+
Example:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
import { failure } from '@pvorona/failable';
|
|
148
|
+
|
|
149
|
+
const f = failure(new Error('boom'));
|
|
150
|
+
f.getOr('default'); // 'default'
|
|
151
|
+
f.or(42).data; // 42
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### `type FailableLike<T, E>`
|
|
155
|
+
|
|
156
|
+
Structured-clone-friendly representation of a result:
|
|
157
|
+
|
|
158
|
+
- `{ status: 'success', data }`
|
|
159
|
+
- `{ status: 'failure', error }`
|
|
160
|
+
|
|
161
|
+
Example:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
import type { FailableLike } from '@pvorona/failable';
|
|
165
|
+
|
|
166
|
+
type Wire = FailableLike<{ id: string }, { code: string }>;
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### `type FailableLikeSuccess<T>`
|
|
170
|
+
|
|
171
|
+
The success-shaped `FailableLike`.
|
|
172
|
+
|
|
173
|
+
Example:
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { FailableStatus, type FailableLikeSuccess } from '@pvorona/failable';
|
|
177
|
+
|
|
178
|
+
const wireOk: FailableLikeSuccess<number> = {
|
|
179
|
+
status: FailableStatus.Success,
|
|
180
|
+
data: 1,
|
|
181
|
+
};
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### `type FailableLikeFailure<E>`
|
|
185
|
+
|
|
186
|
+
The failure-shaped `FailableLike`.
|
|
187
|
+
|
|
188
|
+
Example:
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { FailableStatus, type FailableLikeFailure } from '@pvorona/failable';
|
|
192
|
+
|
|
193
|
+
const wireErr: FailableLikeFailure<string> = {
|
|
194
|
+
status: FailableStatus.Failure,
|
|
195
|
+
error: 'bad_request',
|
|
196
|
+
};
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### `FailableTag`, `SuccessTag`, `FailureTag` (Symbols)
|
|
200
|
+
|
|
201
|
+
Low-level Symbol tags used to mark hydrated `Failable` instances at runtime.
|
|
202
|
+
|
|
203
|
+
Most code should prefer `result.isSuccess` / `result.isError` or the guards `isSuccess(...)` / `isFailure(...)`.
|
|
204
|
+
|
|
205
|
+
Example (advanced):
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
import { FailableTag } from '@pvorona/failable';
|
|
209
|
+
|
|
210
|
+
export function isHydratedFailable(value: unknown): boolean {
|
|
211
|
+
return (
|
|
212
|
+
typeof value === 'object' &&
|
|
213
|
+
value !== null &&
|
|
214
|
+
(value as any)[FailableTag] === true
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### `success<T>(data: T): Success<T>`
|
|
220
|
+
|
|
221
|
+
Example:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
import { success } from '@pvorona/failable';
|
|
225
|
+
|
|
226
|
+
const ok = success({ id: '1' });
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### `failure<E>(error: E): Failure<E>`
|
|
230
|
+
|
|
231
|
+
Example:
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { failure } from '@pvorona/failable';
|
|
235
|
+
|
|
236
|
+
const err = failure({ code: 'bad_request' });
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### `isFailable(value): value is Failable<unknown, unknown>`
|
|
240
|
+
|
|
241
|
+
Checks whether a value is a hydrated `Failable` instance (Symbol-tagged).
|
|
242
|
+
|
|
243
|
+
Example:
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
import { isFailable, success } from '@pvorona/failable';
|
|
247
|
+
|
|
248
|
+
const maybe: unknown = success(1);
|
|
249
|
+
if (isFailable(maybe)) {
|
|
250
|
+
// narrowed
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### `isSuccess(value): value is Success<unknown>`
|
|
255
|
+
|
|
256
|
+
Example:
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
import { isSuccess, success } from '@pvorona/failable';
|
|
260
|
+
|
|
261
|
+
const maybe: unknown = success(1);
|
|
262
|
+
if (isSuccess(maybe)) {
|
|
263
|
+
maybe.data; // ok
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### `isFailure(value): value is Failure<unknown>`
|
|
268
|
+
|
|
269
|
+
Example:
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
import { failure, isFailure } from '@pvorona/failable';
|
|
273
|
+
|
|
274
|
+
const maybe: unknown = failure('nope');
|
|
275
|
+
if (isFailure(maybe)) {
|
|
276
|
+
console.log(maybe.error);
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### `toFailableLike(result): FailableLike<...>`
|
|
281
|
+
|
|
282
|
+
Converts a hydrated `Failable` into a structured-clone-friendly representation.
|
|
283
|
+
|
|
284
|
+
Example:
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
import { success, toFailableLike } from '@pvorona/failable';
|
|
288
|
+
|
|
289
|
+
const res = success(1);
|
|
290
|
+
const wire = toFailableLike(res);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### `isFailableLike(value): value is FailableLike<unknown, unknown>`
|
|
294
|
+
|
|
295
|
+
Strictly checks for `{ status, data }` or `{ status, error }` with no extra enumerable keys.
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
import { isFailableLike } from '@pvorona/failable';
|
|
301
|
+
|
|
302
|
+
const wire: unknown = { status: 'success', data: 1 };
|
|
303
|
+
isFailableLike(wire); // true
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### `createFailable(...)`
|
|
307
|
+
|
|
308
|
+
Overloads:
|
|
309
|
+
|
|
310
|
+
- `createFailable(failable)` → returns the same instance
|
|
311
|
+
- `createFailable(failableLike)` → rehydrates into a real `Success` / `Failure`
|
|
312
|
+
- `createFailable(() => value)` → captures throws into `Failure`
|
|
313
|
+
- `createFailable(promise)` → captures rejections into `Failure`
|
|
314
|
+
|
|
315
|
+
Examples:
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
import { createFailable, failure, toFailableLike } from '@pvorona/failable';
|
|
319
|
+
|
|
320
|
+
// function wrapper (captures throws)
|
|
321
|
+
const res1 = createFailable(() => JSON.parse('{'));
|
|
322
|
+
|
|
323
|
+
// promise wrapper (captures rejections)
|
|
324
|
+
const res2 = await createFailable(fetch('https://example.com'));
|
|
325
|
+
|
|
326
|
+
// rehydrate from structured clone
|
|
327
|
+
const wire = toFailableLike(failure('bad'));
|
|
328
|
+
const hydrated = createFailable(wire);
|
|
50
329
|
```
|
package/dist/index.js
CHANGED
|
@@ -1,80 +1,92 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { notImplemented as
|
|
3
|
-
const
|
|
4
|
-
var
|
|
5
|
-
function
|
|
6
|
-
return
|
|
1
|
+
import { isFunction as F, isObject as e } from "@pvorona/assert";
|
|
2
|
+
import { notImplemented as c } from "@pvorona/not-implemented";
|
|
3
|
+
const f = /* @__PURE__ */ Symbol("Failable"), O = /* @__PURE__ */ Symbol("Success"), l = /* @__PURE__ */ Symbol("Failure");
|
|
4
|
+
var S = /* @__PURE__ */ ((r) => (r.Success = "success", r.Failure = "failure", r))(S || {});
|
|
5
|
+
function g(r) {
|
|
6
|
+
return e(r) && Object.keys(r).length === 2 && Object.getOwnPropertyDescriptor(r, "status")?.value === "success" && Object.prototype.hasOwnProperty.call(r, "data");
|
|
7
7
|
}
|
|
8
|
-
function
|
|
9
|
-
return
|
|
8
|
+
function h(r) {
|
|
9
|
+
return e(r) && Object.keys(r).length === 2 && Object.getOwnPropertyDescriptor(r, "status")?.value === "failure" && Object.prototype.hasOwnProperty.call(r, "error");
|
|
10
|
+
}
|
|
11
|
+
function u(r) {
|
|
12
|
+
return h(r) || g(r);
|
|
10
13
|
}
|
|
11
|
-
const
|
|
12
|
-
[
|
|
14
|
+
const b = {
|
|
15
|
+
[f]: !0,
|
|
13
16
|
isSuccess: !1,
|
|
14
17
|
isError: !1,
|
|
15
18
|
data: null,
|
|
16
19
|
error: null,
|
|
17
|
-
or:
|
|
18
|
-
getOr:
|
|
19
|
-
getOrThrow:
|
|
20
|
-
},
|
|
21
|
-
const r = Object.create(
|
|
22
|
-
return r[
|
|
20
|
+
or: c,
|
|
21
|
+
getOr: c,
|
|
22
|
+
getOrThrow: c
|
|
23
|
+
}, j = (() => {
|
|
24
|
+
const r = Object.create(b);
|
|
25
|
+
return r[O] = !0, r.status = "success", r.isSuccess = !0, r.or = function() {
|
|
23
26
|
return this;
|
|
24
27
|
}, r.getOr = function() {
|
|
25
28
|
return this.data;
|
|
26
29
|
}, r.getOrThrow = function() {
|
|
27
30
|
return this.data;
|
|
28
31
|
}, Object.freeze(r);
|
|
29
|
-
})(),
|
|
30
|
-
const r = Object.create(
|
|
31
|
-
return r[
|
|
32
|
-
return
|
|
33
|
-
}, r.getOr = function(
|
|
34
|
-
return
|
|
32
|
+
})(), m = (() => {
|
|
33
|
+
const r = Object.create(b);
|
|
34
|
+
return r[l] = !0, r.status = "failure", r.isError = !0, r.or = function(s) {
|
|
35
|
+
return n(s);
|
|
36
|
+
}, r.getOr = function(s) {
|
|
37
|
+
return s;
|
|
35
38
|
}, r.getOrThrow = function() {
|
|
36
39
|
throw this.error;
|
|
37
40
|
}, Object.freeze(r);
|
|
38
|
-
})()
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return e.data = r, Object.freeze(e);
|
|
45
|
-
},
|
|
46
|
-
ofError: (r) => {
|
|
47
|
-
const e = Object.create(g);
|
|
48
|
-
return e.error = r, Object.freeze(e);
|
|
49
|
-
},
|
|
50
|
-
toFailableLike: h,
|
|
51
|
-
isFailableLike: (r) => F(r) || O(r),
|
|
52
|
-
from: j
|
|
53
|
-
};
|
|
54
|
-
function h(r) {
|
|
55
|
-
return r.status === "failure" ? { status: "failure", error: r.error } : { status: "success", data: r.data };
|
|
41
|
+
})();
|
|
42
|
+
function o(r) {
|
|
43
|
+
return e(r) && r[f] === !0;
|
|
44
|
+
}
|
|
45
|
+
function E(r) {
|
|
46
|
+
return e(r) && r[O] === !0;
|
|
56
47
|
}
|
|
57
|
-
function
|
|
58
|
-
return
|
|
48
|
+
function T(r) {
|
|
49
|
+
return e(r) && r[l] === !0;
|
|
59
50
|
}
|
|
60
51
|
function n(r) {
|
|
61
|
-
|
|
52
|
+
const t = Object.create(j);
|
|
53
|
+
return t.data = r, Object.freeze(t);
|
|
54
|
+
}
|
|
55
|
+
function i(r) {
|
|
56
|
+
const t = Object.create(m);
|
|
57
|
+
return t.error = r, Object.freeze(t);
|
|
62
58
|
}
|
|
63
|
-
function
|
|
59
|
+
function A(r) {
|
|
60
|
+
return r.status === "failure" ? { status: "failure", error: r.error } : { status: "success", data: r.data };
|
|
61
|
+
}
|
|
62
|
+
function L(r) {
|
|
63
|
+
return o(r) ? r : u(r) ? a(r) : F(r) ? p(r) : y(r);
|
|
64
|
+
}
|
|
65
|
+
function a(r) {
|
|
66
|
+
return r.status === "success" ? n(r.data) : i(r.error);
|
|
67
|
+
}
|
|
68
|
+
function p(r) {
|
|
64
69
|
try {
|
|
65
|
-
const
|
|
66
|
-
return t
|
|
67
|
-
} catch (
|
|
68
|
-
return t
|
|
70
|
+
const t = r();
|
|
71
|
+
return o(t) ? t : u(t) ? a(t) : n(t);
|
|
72
|
+
} catch (t) {
|
|
73
|
+
return i(t);
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
|
-
function
|
|
72
|
-
return r.then((
|
|
76
|
+
function y(r) {
|
|
77
|
+
return Promise.resolve(r).then((t) => o(t) ? t : u(t) ? a(t) : n(t), i);
|
|
73
78
|
}
|
|
74
79
|
export {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
S as FailableStatus,
|
|
81
|
+
f as FailableTag,
|
|
82
|
+
l as FailureTag,
|
|
83
|
+
O as SuccessTag,
|
|
84
|
+
L as createFailable,
|
|
85
|
+
i as failure,
|
|
86
|
+
o as isFailable,
|
|
87
|
+
u as isFailableLike,
|
|
88
|
+
T as isFailure,
|
|
89
|
+
E as isSuccess,
|
|
90
|
+
n as success,
|
|
91
|
+
A as toFailableLike
|
|
80
92
|
};
|
package/dist/lib/failable.d.ts
CHANGED
|
@@ -14,8 +14,8 @@ export type Failable<T, E> = Success<T> | Failure<E>;
|
|
|
14
14
|
* A {@link Failable} instance relies on Symbols and prototype methods, which do not survive structured cloning.
|
|
15
15
|
*
|
|
16
16
|
* Boundary rule:
|
|
17
|
-
* - **sender**: `
|
|
18
|
-
* - **receiver**: `
|
|
17
|
+
* - **sender**: `toFailableLike(result)`
|
|
18
|
+
* - **receiver**: `createFailable(message.result)` (rehydrates into a real {@link Failable})
|
|
19
19
|
*
|
|
20
20
|
* Note: `data` / `error` must themselves be structured-cloneable.
|
|
21
21
|
*/
|
|
@@ -28,6 +28,7 @@ export type FailableLikeFailure<E> = {
|
|
|
28
28
|
readonly status: FailableStatus.Failure;
|
|
29
29
|
readonly error: E;
|
|
30
30
|
};
|
|
31
|
+
export declare function isFailableLike(value: unknown): value is FailableLike<unknown, unknown>;
|
|
31
32
|
export type Success<T> = {
|
|
32
33
|
readonly [FailableTag]: true;
|
|
33
34
|
readonly [SuccessTag]: true;
|
|
@@ -53,7 +54,7 @@ export type Failure<E> = {
|
|
|
53
54
|
readonly getOrThrow: () => never;
|
|
54
55
|
};
|
|
55
56
|
/**
|
|
56
|
-
*
|
|
57
|
+
* Factory + utilities for the {@link Failable} result type.
|
|
57
58
|
*
|
|
58
59
|
* `Failable<T, E>` is a discriminated union of:
|
|
59
60
|
* - {@link Success}: `{ status: 'success', isSuccess: true, data: T, error: null }`
|
|
@@ -67,59 +68,54 @@ export type Failure<E> = {
|
|
|
67
68
|
* Runtime model / invariants:
|
|
68
69
|
* - Instances are shallow-immutable (`Object.freeze`) and tagged with Symbols.
|
|
69
70
|
* - They are NOT class instances; do not use `instanceof`. Prefer `result.isSuccess` / `result.isError`
|
|
70
|
-
* or the guards {@link
|
|
71
|
+
* or the guards {@link isSuccess} / {@link isFailure}.
|
|
71
72
|
* - Exactly one of `data` / `error` is non-null.
|
|
72
73
|
*
|
|
73
74
|
* Structured-clone boundary rule (RPC, `postMessage`, `chrome.*` messaging):
|
|
74
|
-
* - **sender**: `
|
|
75
|
-
* - **receiver**: `
|
|
75
|
+
* - **sender**: `toFailableLike(result)`
|
|
76
|
+
* - **receiver**: `createFailable(payload)` (rehydrates methods + Symbol tags)
|
|
76
77
|
*
|
|
77
|
-
* `
|
|
78
|
-
* - `
|
|
79
|
-
* - `
|
|
80
|
-
* - `
|
|
78
|
+
* `createFailable(...)` overloads:
|
|
79
|
+
* - `createFailable(failable)` returns the same instance (no wrapping).
|
|
80
|
+
* - `createFailable(failableLike)` rehydrates into a real `Success` / `Failure`.
|
|
81
|
+
* - `createFailable(() => value)` captures thrown values into `Failure` and preserves/rehydrates returned
|
|
81
82
|
* `Failable` / `FailableLike`.
|
|
82
|
-
* - `
|
|
83
|
+
* - `createFailable(promise)` captures rejection values into `Failure` and preserves/rehydrates resolved
|
|
83
84
|
* `Failable` / `FailableLike`.
|
|
84
85
|
*
|
|
85
86
|
* Gotchas:
|
|
86
|
-
* - `
|
|
87
|
+
* - `isFailableLike` is intentionally strict: only `{ status, data }` or `{ status, error }`
|
|
87
88
|
* with no extra enumerable keys. If you need metadata, wrap it: `{ result: failableLike, meta }`.
|
|
88
89
|
* - `or(...)` and `getOr(...)` are eager (fallback is evaluated before the call). Use branching for
|
|
89
90
|
* lazy fallbacks.
|
|
90
91
|
* - No error normalization is performed: whatever you throw/reject becomes `.error`.
|
|
91
|
-
* - `
|
|
92
|
+
* - `createFailable(() => somePromise)` does NOT await; pass the promise directly: `createFailable(somePromise)`.
|
|
92
93
|
*
|
|
93
94
|
* @example
|
|
94
|
-
* const res =
|
|
95
|
+
* const res = createFailable(() => JSON.parse(text));
|
|
95
96
|
* if (res.isSuccess) return res.data;
|
|
96
97
|
* console.error(res.error);
|
|
97
98
|
*
|
|
98
99
|
* @example
|
|
99
100
|
* // Structured-clone transport
|
|
100
|
-
* const wire =
|
|
101
|
+
* const wire = toFailableLike(res);
|
|
101
102
|
* // ... send wire ...
|
|
102
|
-
* const hydrated =
|
|
103
|
+
* const hydrated = createFailable(wire);
|
|
103
104
|
*/
|
|
104
|
-
export declare
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
readonly from: typeof from;
|
|
113
|
-
};
|
|
114
|
-
declare function toFailableLike<T>(value: Success<T>): FailableLikeSuccess<T>;
|
|
115
|
-
declare function toFailableLike<E>(value: Failure<E>): FailableLikeFailure<E>;
|
|
116
|
-
declare function toFailableLike<T, E>(value: Failable<T, E>): FailableLike<T, E>;
|
|
105
|
+
export declare function isFailable(value: unknown): value is Failable<unknown, unknown>;
|
|
106
|
+
export declare function isSuccess(value: unknown): value is Success<unknown>;
|
|
107
|
+
export declare function isFailure(value: unknown): value is Failure<unknown>;
|
|
108
|
+
export declare function success<T = void>(data: T): Success<T>;
|
|
109
|
+
export declare function failure<E = void>(error: E): Failure<E>;
|
|
110
|
+
export declare function toFailableLike<T>(value: Success<T>): FailableLikeSuccess<T>;
|
|
111
|
+
export declare function toFailableLike<E>(value: Failure<E>): FailableLikeFailure<E>;
|
|
112
|
+
export declare function toFailableLike<T, E>(value: Failable<T, E>): FailableLike<T, E>;
|
|
117
113
|
type InferReturnTypeFromFunction<F extends () => R, E = Error, R = ReturnType<F>> = [R] extends [never] ? Failure<E> : R extends Success<infer A> ? Success<A> : R extends Failure<infer A> ? Failure<A> : R extends FailableLikeSuccess<infer A> ? Success<A> : R extends FailableLikeFailure<infer A> ? Failure<A> : R extends Failable<infer A, infer B> ? Failable<A, B> : Failable<R, E>;
|
|
118
114
|
type InferReturnTypeFromPromise<T, E = Error, P extends PromiseLike<T> = PromiseLike<T>> = [Awaited<P>] extends [never] ? Promise<Failure<E>> : Awaited<P> extends Promise<Success<infer A>> ? Promise<Success<A>> : Awaited<P> extends Promise<Failure<infer A>> ? Promise<Failure<A>> : Awaited<P> extends Failable<unknown, unknown> ? Promise<Awaited<P>> : Awaited<P> extends FailableLikeSuccess<infer A> ? Promise<Success<A>> : Awaited<P> extends FailableLikeFailure<infer A> ? Promise<Failure<A>> : Awaited<P> extends FailableLike<infer A, infer B> ? Promise<Failable<A, B>> : Promise<Failable<Awaited<P>, E>>;
|
|
119
|
-
declare function
|
|
120
|
-
declare function
|
|
121
|
-
declare function
|
|
122
|
-
declare function
|
|
123
|
-
declare function
|
|
115
|
+
export declare function createFailable<T>(value: FailableLikeSuccess<T>): Success<T>;
|
|
116
|
+
export declare function createFailable<E>(value: FailableLikeFailure<E>): Failure<E>;
|
|
117
|
+
export declare function createFailable<T, E>(value: FailableLike<T, E>): Failable<T, E>;
|
|
118
|
+
export declare function createFailable<F extends () => R, E = Error, R = ReturnType<F>>(fun: F): InferReturnTypeFromFunction<F, E, R>;
|
|
119
|
+
export declare function createFailable<T, E = Error, P extends PromiseLike<T> = PromiseLike<T>>(promise: P): InferReturnTypeFromPromise<T, E, P>;
|
|
124
120
|
export {};
|
|
125
121
|
//# sourceMappingURL=failable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failable.d.ts","sourceRoot":"","sources":["../../src/lib/failable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAErE,0BAAkB,cAAc;IAC9B,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAErD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,EAAE,CAAC,IACzB,mBAAmB,CAAC,CAAC,CAAC,GACtB,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAE3B,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI;IACnC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI;IACnC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB,CAAC;AA0BF,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IACvB,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC;IAC7B,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IACvB,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC;IAC7B,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,KAAK,CAAC;CAClC,CAAC;AA+CF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,
|
|
1
|
+
{"version":3,"file":"failable.d.ts","sourceRoot":"","sources":["../../src/lib/failable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAErE,0BAAkB,cAAc;IAC9B,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAErD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,EAAE,CAAC,IACzB,mBAAmB,CAAC,CAAC,CAAC,GACtB,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAE3B,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI;IACnC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI;IACnC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB,CAAC;AA0BF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAEzC;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IACvB,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC;IAC7B,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IACvB,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC;IAC7B,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,KAAK,CAAC;CAClC,CAAC;AA+CF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAErC;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAEnE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAEnE;AAED,wBAAgB,OAAO,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAIrD;AAED,wBAAgB,OAAO,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAItD;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAC7E,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAC7E,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAShF,KAAK,2BAA2B,CAC9B,CAAC,SAAS,MAAM,CAAC,EACjB,CAAC,GAAG,KAAK,EACT,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IACf,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,GACV,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,GACV,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,GACV,CAAC,SAAS,mBAAmB,CAAC,MAAM,CAAC,CAAC,GACtC,OAAO,CAAC,CAAC,CAAC,GACV,CAAC,SAAS,mBAAmB,CAAC,MAAM,CAAC,CAAC,GACtC,OAAO,CAAC,CAAC,CAAC,GACV,CAAC,SAAS,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GACpC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,GACd,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEnB,KAAK,0BAA0B,CAC7B,CAAC,EACD,CAAC,GAAG,KAAK,EACT,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,IACvC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC5B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAC5C,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAC5C,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,GAC7C,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,mBAAmB,CAAC,MAAM,CAAC,CAAC,GAC/C,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,mBAAmB,CAAC,MAAM,CAAC,CAAC,GAC/C,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GACjD,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAErC,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7E,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7E,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAChF,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAC5E,GAAG,EAAE,CAAC,GACL,2BAA2B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACxC,wBAAgB,cAAc,CAC5B,CAAC,EACD,CAAC,GAAG,KAAK,EACT,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,EAEzC,OAAO,EAAE,CAAC,GACT,0BAA0B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pvorona/failable",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"main": "./dist/index.js",
|
|
6
7
|
"module": "./dist/index.js",
|
|
@@ -18,8 +19,11 @@
|
|
|
18
19
|
"dist",
|
|
19
20
|
"!**/*.tsbuildinfo"
|
|
20
21
|
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
21
25
|
"dependencies": {
|
|
22
|
-
"@pvorona/assert": "
|
|
23
|
-
"@pvorona/not-implemented": "
|
|
26
|
+
"@pvorona/assert": "~0.0.2",
|
|
27
|
+
"@pvorona/not-implemented": "~0.0.1"
|
|
24
28
|
}
|
|
25
29
|
}
|