ts-data-forge 1.0.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.
Files changed (143) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +534 -0
  3. package/package.json +101 -0
  4. package/src/array/array-utils-creation.test.mts +443 -0
  5. package/src/array/array-utils-modification.test.mts +197 -0
  6. package/src/array/array-utils-overload-type-error.test.mts +149 -0
  7. package/src/array/array-utils-reducing-value.test.mts +425 -0
  8. package/src/array/array-utils-search.test.mts +169 -0
  9. package/src/array/array-utils-set-op.test.mts +335 -0
  10. package/src/array/array-utils-slice-clamped.test.mts +113 -0
  11. package/src/array/array-utils-slicing.test.mts +316 -0
  12. package/src/array/array-utils-transformation.test.mts +790 -0
  13. package/src/array/array-utils-validation.test.mts +492 -0
  14. package/src/array/array-utils.mts +4000 -0
  15. package/src/array/array.test.mts +146 -0
  16. package/src/array/index.mts +2 -0
  17. package/src/array/tuple-utils.mts +519 -0
  18. package/src/array/tuple-utils.test.mts +518 -0
  19. package/src/collections/imap-mapped.mts +801 -0
  20. package/src/collections/imap-mapped.test.mts +860 -0
  21. package/src/collections/imap.mts +651 -0
  22. package/src/collections/imap.test.mts +932 -0
  23. package/src/collections/index.mts +6 -0
  24. package/src/collections/iset-mapped.mts +889 -0
  25. package/src/collections/iset-mapped.test.mts +1187 -0
  26. package/src/collections/iset.mts +682 -0
  27. package/src/collections/iset.test.mts +1084 -0
  28. package/src/collections/queue.mts +390 -0
  29. package/src/collections/queue.test.mts +282 -0
  30. package/src/collections/stack.mts +423 -0
  31. package/src/collections/stack.test.mts +225 -0
  32. package/src/expect-type.mts +206 -0
  33. package/src/functional/index.mts +4 -0
  34. package/src/functional/match.mts +300 -0
  35. package/src/functional/match.test.mts +177 -0
  36. package/src/functional/optional.mts +733 -0
  37. package/src/functional/optional.test.mts +619 -0
  38. package/src/functional/pipe.mts +212 -0
  39. package/src/functional/pipe.test.mts +85 -0
  40. package/src/functional/result.mts +1134 -0
  41. package/src/functional/result.test.mts +777 -0
  42. package/src/globals.d.mts +38 -0
  43. package/src/guard/has-key.mts +119 -0
  44. package/src/guard/has-key.test.mts +219 -0
  45. package/src/guard/index.mts +7 -0
  46. package/src/guard/is-non-empty-string.mts +108 -0
  47. package/src/guard/is-non-empty-string.test.mts +91 -0
  48. package/src/guard/is-non-null-object.mts +106 -0
  49. package/src/guard/is-non-null-object.test.mts +90 -0
  50. package/src/guard/is-primitive.mts +165 -0
  51. package/src/guard/is-primitive.test.mts +102 -0
  52. package/src/guard/is-record.mts +153 -0
  53. package/src/guard/is-record.test.mts +112 -0
  54. package/src/guard/is-type.mts +450 -0
  55. package/src/guard/is-type.test.mts +496 -0
  56. package/src/guard/key-is-in.mts +163 -0
  57. package/src/guard/key-is-in.test.mts +19 -0
  58. package/src/index.mts +10 -0
  59. package/src/iterator/index.mts +1 -0
  60. package/src/iterator/range.mts +120 -0
  61. package/src/iterator/range.test.mts +33 -0
  62. package/src/json/index.mts +1 -0
  63. package/src/json/json.mts +711 -0
  64. package/src/json/json.test.mts +628 -0
  65. package/src/number/branded-types/finite-number.mts +354 -0
  66. package/src/number/branded-types/finite-number.test.mts +135 -0
  67. package/src/number/branded-types/index.mts +26 -0
  68. package/src/number/branded-types/int.mts +278 -0
  69. package/src/number/branded-types/int.test.mts +140 -0
  70. package/src/number/branded-types/int16.mts +192 -0
  71. package/src/number/branded-types/int16.test.mts +170 -0
  72. package/src/number/branded-types/int32.mts +193 -0
  73. package/src/number/branded-types/int32.test.mts +170 -0
  74. package/src/number/branded-types/non-negative-finite-number.mts +223 -0
  75. package/src/number/branded-types/non-negative-finite-number.test.mts +188 -0
  76. package/src/number/branded-types/non-negative-int16.mts +187 -0
  77. package/src/number/branded-types/non-negative-int16.test.mts +201 -0
  78. package/src/number/branded-types/non-negative-int32.mts +187 -0
  79. package/src/number/branded-types/non-negative-int32.test.mts +204 -0
  80. package/src/number/branded-types/non-zero-finite-number.mts +229 -0
  81. package/src/number/branded-types/non-zero-finite-number.test.mts +198 -0
  82. package/src/number/branded-types/non-zero-int.mts +167 -0
  83. package/src/number/branded-types/non-zero-int.test.mts +177 -0
  84. package/src/number/branded-types/non-zero-int16.mts +196 -0
  85. package/src/number/branded-types/non-zero-int16.test.mts +195 -0
  86. package/src/number/branded-types/non-zero-int32.mts +196 -0
  87. package/src/number/branded-types/non-zero-int32.test.mts +197 -0
  88. package/src/number/branded-types/non-zero-safe-int.mts +196 -0
  89. package/src/number/branded-types/non-zero-safe-int.test.mts +232 -0
  90. package/src/number/branded-types/non-zero-uint16.mts +189 -0
  91. package/src/number/branded-types/non-zero-uint16.test.mts +199 -0
  92. package/src/number/branded-types/non-zero-uint32.mts +189 -0
  93. package/src/number/branded-types/non-zero-uint32.test.mts +199 -0
  94. package/src/number/branded-types/positive-finite-number.mts +241 -0
  95. package/src/number/branded-types/positive-finite-number.test.mts +204 -0
  96. package/src/number/branded-types/positive-int.mts +304 -0
  97. package/src/number/branded-types/positive-int.test.mts +176 -0
  98. package/src/number/branded-types/positive-int16.mts +188 -0
  99. package/src/number/branded-types/positive-int16.test.mts +197 -0
  100. package/src/number/branded-types/positive-int32.mts +188 -0
  101. package/src/number/branded-types/positive-int32.test.mts +197 -0
  102. package/src/number/branded-types/positive-safe-int.mts +187 -0
  103. package/src/number/branded-types/positive-safe-int.test.mts +210 -0
  104. package/src/number/branded-types/positive-uint16.mts +188 -0
  105. package/src/number/branded-types/positive-uint16.test.mts +203 -0
  106. package/src/number/branded-types/positive-uint32.mts +188 -0
  107. package/src/number/branded-types/positive-uint32.test.mts +203 -0
  108. package/src/number/branded-types/safe-int.mts +291 -0
  109. package/src/number/branded-types/safe-int.test.mts +170 -0
  110. package/src/number/branded-types/safe-uint.mts +187 -0
  111. package/src/number/branded-types/safe-uint.test.mts +176 -0
  112. package/src/number/branded-types/uint.mts +179 -0
  113. package/src/number/branded-types/uint.test.mts +158 -0
  114. package/src/number/branded-types/uint16.mts +186 -0
  115. package/src/number/branded-types/uint16.test.mts +170 -0
  116. package/src/number/branded-types/uint32.mts +218 -0
  117. package/src/number/branded-types/uint32.test.mts +170 -0
  118. package/src/number/enum/index.mts +2 -0
  119. package/src/number/enum/int8.mts +344 -0
  120. package/src/number/enum/int8.test.mts +180 -0
  121. package/src/number/enum/uint8.mts +293 -0
  122. package/src/number/enum/uint8.test.mts +164 -0
  123. package/src/number/index.mts +4 -0
  124. package/src/number/num.mts +604 -0
  125. package/src/number/num.test.mts +242 -0
  126. package/src/number/refined-number-utils.mts +566 -0
  127. package/src/object/index.mts +1 -0
  128. package/src/object/object.mts +447 -0
  129. package/src/object/object.test.mts +124 -0
  130. package/src/others/cast-mutable.mts +113 -0
  131. package/src/others/cast-readonly.mts +192 -0
  132. package/src/others/cast-readonly.test.mts +89 -0
  133. package/src/others/if-then.mts +98 -0
  134. package/src/others/if-then.test.mts +75 -0
  135. package/src/others/index.mts +7 -0
  136. package/src/others/map-nullable.mts +172 -0
  137. package/src/others/map-nullable.test.mts +297 -0
  138. package/src/others/memoize-function.mts +196 -0
  139. package/src/others/memoize-function.test.mts +168 -0
  140. package/src/others/tuple.mts +160 -0
  141. package/src/others/tuple.test.mts +11 -0
  142. package/src/others/unknown-to-string.mts +215 -0
  143. package/src/others/unknown-to-string.test.mts +114 -0
@@ -0,0 +1,1134 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-type-assertion */
2
+ import { isRecord } from '../guard/index.mjs';
3
+ import { unknownToString } from '../others/index.mjs';
4
+ import { Optional } from './optional.mjs';
5
+
6
+ /** @internal Symbol to identify the 'Ok' variant of Result. */
7
+ const OkTypeSymbol: unique symbol = Symbol('Result.ok');
8
+
9
+ /** @internal Symbol to identify the 'Err' variant of Result. */
10
+ const ErrTypeSymbol: unique symbol = Symbol('Result.err');
11
+
12
+ /**
13
+ * @internal
14
+ * Represents the 'Ok' variant of a Result, containing a success value.
15
+ * @template S The type of the success value.
16
+ */
17
+ type Ok_<S> = Readonly<{
18
+ /** Discriminant property for the 'Ok' type. */
19
+ type: typeof OkTypeSymbol;
20
+ /** The success value. */
21
+ value: S;
22
+ }>;
23
+
24
+ /**
25
+ * @internal
26
+ * Represents the 'Err' variant of a Result, containing an error value.
27
+ * @template E The type of the error value.
28
+ */
29
+ type Err_<E> = Readonly<{
30
+ /** Discriminant property for the 'Err' type. */
31
+ type: typeof ErrTypeSymbol;
32
+ /** The error value. */
33
+ value: E;
34
+ }>;
35
+
36
+ /**
37
+ * Represents a value that can either be a success (`Ok`) or an error (`Err`).
38
+ * @template S The type of the success value.
39
+ * @template E The type of the error value.
40
+ */
41
+ export type Result<S, E> = Ok_<S> | Err_<E>;
42
+
43
+ /**
44
+ * Namespace for the `Result` type and related functions.
45
+ * Provides utilities to handle operations that can succeed or fail.
46
+ */
47
+ export namespace Result {
48
+ /**
49
+ * Checks if the given value is a `Result`.
50
+ * @param maybeOptional The value to check.
51
+ * @returns `true` if the value is a `Result`, otherwise `false`.
52
+ */
53
+ export const isResult = (
54
+ maybeOptional: unknown,
55
+ ): maybeOptional is Result<unknown, unknown> =>
56
+ isRecord(maybeOptional) &&
57
+ Object.hasOwn(maybeOptional, 'type') &&
58
+ Object.hasOwn(maybeOptional, 'value') &&
59
+ (maybeOptional['type'] === ErrTypeSymbol ||
60
+ maybeOptional['type'] === OkTypeSymbol);
61
+
62
+ /**
63
+ * Represents a `Result` that is a success, containing a value.
64
+ * @template S The type of the success value.
65
+ */
66
+ export type Ok<S> = Ok_<S>;
67
+
68
+ /**
69
+ * Represents a `Result` that is an error, containing an error value.
70
+ * @template E The type of the error value.
71
+ */
72
+ export type Err<E> = Err_<E>;
73
+
74
+ /**
75
+ * Base type for any `Result`, used for generic constraints.
76
+ * Represents a `Result` with unknown success and error types.
77
+ */
78
+ export type Base = Result<unknown, unknown>;
79
+
80
+ /**
81
+ * Extracts the success value type `S` from a `Result.Ok<S>`.
82
+ * If the `Result` is `Result.Err<E>`, resolves to `never`.
83
+ * @template R The `Result.Base` type to unwrap.
84
+ */
85
+ export type UnwrapOk<R extends Base> = R extends Ok<infer S> ? S : never;
86
+
87
+ /**
88
+ * Extracts the error value type `E` from a `Result.Err<E>`.
89
+ * If the `Result` is `Result.Ok<S>`, resolves to `never`.
90
+ * @template R The `Result.Base` type to unwrap.
91
+ */
92
+ export type UnwrapErr<R extends Base> = R extends Err<infer E> ? E : never;
93
+
94
+ /**
95
+ * Narrows a `Result.Base` type to `Result.Ok<S>` if it is an `Ok`.
96
+ * If the `Result` is `Result.Err<E>`, resolves to `never`.
97
+ * @template R The `Result.Base` type to narrow.
98
+ */
99
+ export type NarrowToOk<R extends Base> = R extends Err<unknown> ? never : R;
100
+
101
+ /**
102
+ * Narrows a `Result.Base` type to `Result.Err<E>` if it is an `Err`.
103
+ * If the `Result` is `Result.Ok<S>`, resolves to `never`.
104
+ * @template R The `Result.Base` type to narrow.
105
+ */
106
+ export type NarrowToErr<R extends Base> = R extends Ok<unknown> ? never : R;
107
+
108
+ /**
109
+ * Creates a `Result.Ok` containing the given success value.
110
+ *
111
+ * Use this constructor when an operation succeeds and you want to wrap
112
+ * the successful result in a Result type for consistent error handling.
113
+ *
114
+ * @template S The type of the success value.
115
+ * @param value The success value.
116
+ * @returns A `Result.Ok<S>` containing the value.
117
+ * @example
118
+ * ```typescript
119
+ * // Basic success case
120
+ * const success = Result.ok(42);
121
+ * console.log(Result.isOk(success)); // true
122
+ * console.log(Result.unwrapOk(success)); // 42
123
+ *
124
+ * // Function that returns a Result
125
+ * function divide(a: number, b: number): Result<number, string> {
126
+ * if (b === 0) {
127
+ * return Result.err("Division by zero");
128
+ * }
129
+ * return Result.ok(a / b);
130
+ * }
131
+ *
132
+ * const result = divide(10, 2);
133
+ * console.log(Result.unwrapOk(result)); // 5
134
+ * ```
135
+ */
136
+ export const ok = <S,>(value: S): Ok<S> => ({
137
+ type: OkTypeSymbol,
138
+ value,
139
+ });
140
+
141
+ /**
142
+ * Creates a `Result.Err` containing the given error value.
143
+ *
144
+ * Use this constructor when an operation fails and you want to wrap
145
+ * the error information in a Result type for consistent error handling.
146
+ *
147
+ * @template E The type of the error value.
148
+ * @param value The error value.
149
+ * @returns A `Result.Err<E>` containing the value.
150
+ * @example
151
+ * ```typescript
152
+ * // Basic error case
153
+ * const failure = Result.err("Something went wrong");
154
+ * console.log(Result.isErr(failure)); // true
155
+ * console.log(Result.unwrapErr(failure)); // "Something went wrong"
156
+ *
157
+ * // Function that can fail
158
+ * function parseInteger(input: string): Result<number, string> {
159
+ * const num = parseInt(input, 10);
160
+ * if (isNaN(num)) {
161
+ * return Result.err(`Invalid number format: ${input}`);
162
+ * }
163
+ * return Result.ok(num);
164
+ * }
165
+ *
166
+ * const result = parseInteger("abc");
167
+ * console.log(Result.unwrapErr(result)); // "Invalid number format: abc"
168
+ *
169
+ * // Using custom error types
170
+ * interface ValidationError {
171
+ * field: string;
172
+ * message: string;
173
+ * }
174
+ *
175
+ * const validationError = Result.err<ValidationError>({
176
+ * field: "email",
177
+ * message: "Invalid email format"
178
+ * });
179
+ * ```
180
+ */
181
+ export const err = <E,>(value: E): Err<E> => ({
182
+ type: ErrTypeSymbol,
183
+ value,
184
+ });
185
+
186
+ /**
187
+ * @internal
188
+ * Default string conversion function using native String constructor.
189
+ */
190
+ const toStr_ = String;
191
+
192
+ /**
193
+ * Checks if a `Result` is `Result.Ok`.
194
+ * Acts as a type guard, narrowing the type to the success variant.
195
+ *
196
+ * This function is essential for type-safe Result handling, allowing
197
+ * TypeScript to understand that subsequent operations will work with
198
+ * the success value rather than the error value.
199
+ *
200
+ * @template R The `Result.Base` type to check.
201
+ * @param result The `Result` to check.
202
+ * @returns `true` if the `Result` is `Result.Ok`, otherwise `false`.
203
+ * @example
204
+ * ```typescript
205
+ * // Basic type guard usage
206
+ * const result: Result<number, string> = divide(10, 2);
207
+ *
208
+ * if (Result.isOk(result)) {
209
+ * // TypeScript knows result is Result.Ok<number>
210
+ * console.log(result.value); // Safe to access .value
211
+ * console.log(Result.unwrapOk(result)); // 5
212
+ * } else {
213
+ * // TypeScript knows result is Result.Err<string>
214
+ * console.log(result.value); // Error message
215
+ * }
216
+ *
217
+ * // Using in conditional logic
218
+ * const processResult = (r: Result<string, Error>) => {
219
+ * return Result.isOk(r)
220
+ * ? r.value.toUpperCase() // Safe string operations
221
+ * : "Error occurred";
222
+ * };
223
+ *
224
+ * // Filtering arrays of Results
225
+ * const results: Result<number, string>[] = [
226
+ * Result.ok(1),
227
+ * Result.err("error"),
228
+ * Result.ok(2)
229
+ * ];
230
+ * const successes = results.filter(Result.isOk);
231
+ * // successes is Result.Ok<number>[]
232
+ * ```
233
+ */
234
+ export const isOk = <R extends Base>(result: R): result is NarrowToOk<R> =>
235
+ result.type === OkTypeSymbol;
236
+
237
+ /**
238
+ * Checks if a `Result` is `Result.Err`.
239
+ * Acts as a type guard, narrowing the type to the error variant.
240
+ *
241
+ * This function is essential for type-safe Result handling, allowing
242
+ * TypeScript to understand that subsequent operations will work with
243
+ * the error value rather than the success value.
244
+ *
245
+ * @template R The `Result.Base` type to check.
246
+ * @param result The `Result` to check.
247
+ * @returns `true` if the `Result` is `Result.Err`, otherwise `false`.
248
+ * @example
249
+ * ```typescript
250
+ * // Basic type guard usage
251
+ * const result: Result<number, string> = divide(10, 0);
252
+ *
253
+ * if (Result.isErr(result)) {
254
+ * // TypeScript knows result is Result.Err<string>
255
+ * console.log(result.value); // Safe to access error .value
256
+ * console.log(Result.unwrapErr(result)); // "Division by zero"
257
+ * } else {
258
+ * // TypeScript knows result is Result.Ok<number>
259
+ * console.log(result.value); // Success value
260
+ * }
261
+ *
262
+ * // Error handling patterns
263
+ * const handleResult = (r: Result<Data, ApiError>) => {
264
+ * if (Result.isErr(r)) {
265
+ * logError(r.value); // Safe error operations
266
+ * return null;
267
+ * }
268
+ * return processData(r.value);
269
+ * };
270
+ *
271
+ * // Collecting errors from multiple Results
272
+ * const results: Result<string, ValidationError>[] = validateForm();
273
+ * const errors = results
274
+ * .filter(Result.isErr)
275
+ * .map(err => err.value); // ValidationError[]
276
+ * ```
277
+ */
278
+ export const isErr = <R extends Base>(result: R): result is NarrowToErr<R> =>
279
+ result.type === ErrTypeSymbol;
280
+
281
+ /**
282
+ * Unwraps a `Result`, returning the success value.
283
+ * Throws an error if the `Result` is `Result.Err`.
284
+ *
285
+ * This is useful when you're confident that a Result should contain a success value
286
+ * and want to treat errors as exceptional conditions. The error message will be
287
+ * constructed from the error value using the provided string conversion function.
288
+ *
289
+ * @template R The `Result.Base` type to unwrap.
290
+ * @param result The `Result` to unwrap.
291
+ * @param toStr An optional function to convert the error value to a string for the error message. Defaults to `String`.
292
+ * @returns The success value if `Result.Ok`.
293
+ * @throws {Error} Error with the stringified error value if the `Result` is `Result.Err`.
294
+ * @example
295
+ * ```typescript
296
+ * // Basic usage with default string conversion
297
+ * const success = Result.ok(42);
298
+ * console.log(Result.unwrapThrow(success)); // 42
299
+ *
300
+ * const failure = Result.err("Network error");
301
+ * try {
302
+ * Result.unwrapThrow(failure); // throws Error: "Network error"
303
+ * } catch (error) {
304
+ * console.log(error.message); // "Network error"
305
+ * }
306
+ *
307
+ * // Custom error string conversion
308
+ * interface ApiError {
309
+ * code: number;
310
+ * message: string;
311
+ * }
312
+ *
313
+ * const apiResult = Result.err<ApiError>({ code: 404, message: "Not found" });
314
+ * try {
315
+ * Result.unwrapThrow(apiResult, err => `API Error ${err.code}: ${err.message}`);
316
+ * } catch (error) {
317
+ * console.log(error.message); // "API Error 404: Not found"
318
+ * }
319
+ *
320
+ * // In contexts where failure is unexpected
321
+ * const configResult = loadConfiguration();
322
+ * const config = Result.unwrapThrow(configResult, err =>
323
+ * `Failed to load configuration: ${err}`
324
+ * ); // Will throw if config loading fails
325
+ * ```
326
+ */
327
+ export const unwrapThrow = <R extends Base>(
328
+ result: R,
329
+ toStr: (e: UnwrapErr<R>) => string = toStr_,
330
+ ): UnwrapOk<R> => {
331
+ if (isErr(result)) {
332
+ throw new Error(toStr(result.value as UnwrapErr<R>));
333
+ }
334
+
335
+ return result.value as UnwrapOk<R>;
336
+ };
337
+
338
+ /**
339
+ * Unwraps a `Result`, returning the success value or `undefined` if it's an error.
340
+ *
341
+ * This function provides a safe way to extract success values from Results without
342
+ * throwing exceptions. It has overloaded behavior based on the type:
343
+ * - For `Result.Ok<T>`: Always returns `T` (guaranteed by type system)
344
+ * - For general `Result<T, E>`: Returns `T | undefined`
345
+ *
346
+ * @template R The `Result.Base` type to unwrap.
347
+ * @param result The `Result` to unwrap.
348
+ * @returns The success value if `Result.Ok`, otherwise `undefined`.
349
+ * @example
350
+ * ```typescript
351
+ * // With guaranteed Ok - returns the value
352
+ * const success = Result.ok(42);
353
+ * const value = Result.unwrapOk(success); // Type: number, Value: 42
354
+ *
355
+ * // With general Result - may return undefined
356
+ * const maybeResult: Result<string, Error> = fetchData();
357
+ * const data = Result.unwrapOk(maybeResult); // Type: string | undefined
358
+ *
359
+ * // Safe pattern for handling both cases
360
+ * const result = Result.ok("hello");
361
+ * const unwrapped = Result.unwrapOk(result);
362
+ * if (unwrapped !== undefined) {
363
+ * console.log(unwrapped.toUpperCase()); // "HELLO"
364
+ * }
365
+ *
366
+ * // Useful in conditional chains
367
+ * const processResult = (r: Result<number, string>) => {
368
+ * const value = Result.unwrapOk(r);
369
+ * return value !== undefined ? value * 2 : 0;
370
+ * };
371
+ * ```
372
+ */
373
+ export const unwrapOk: UnwrapOkFnOverload = (<R extends Base>(
374
+ result: R,
375
+ ): UnwrapOk<R> | undefined =>
376
+ isErr(result)
377
+ ? undefined
378
+ : (result.value as UnwrapOk<R>)) as UnwrapOkFnOverload;
379
+
380
+ type UnwrapOkFnOverload = {
381
+ <R extends Ok<unknown>>(result: R): UnwrapOk<R>;
382
+
383
+ // Curried version
384
+ <R extends Base>(result: R): UnwrapOk<R> | undefined;
385
+ };
386
+
387
+ /**
388
+ * Unwraps a `Result`, returning the success value or a default value if it is `Result.Err`.
389
+ * @template R The `Result.Base` type to unwrap.
390
+ * @template D The type of the default value.
391
+ * @param result The `Result` to unwrap.
392
+ * @param defaultValue The value to return if `result` is `Result.Err`.
393
+ * @returns The success value if `Result.Ok`, otherwise `defaultValue`.
394
+ * @example
395
+ * ```typescript
396
+ * // Regular usage
397
+ * const result = Result.ok(42);
398
+ * const value = Result.unwrapOkOr(result, 0);
399
+ * console.log(value); // 42
400
+ *
401
+ * // Curried usage for pipe composition
402
+ * const unwrapWithDefault = Result.unwrapOkOr(0);
403
+ * const value2 = pipe(Result.err("error")).map(unwrapWithDefault).value;
404
+ * console.log(value2); // 0
405
+ * ```
406
+ */
407
+ export const unwrapOkOr: UnwrapOkOrFnOverload = (<R extends Base, D>(
408
+ ...args: readonly [result: R, defaultValue: D] | readonly [defaultValue: D]
409
+ ):
410
+ | D
411
+ | UnwrapOk<R>
412
+ | (<E>(result: Result<UnwrapOk<R>, E>) => D | UnwrapOk<R>) => {
413
+ switch (args.length) {
414
+ case 2: {
415
+ // Direct version: first argument is result
416
+ const [result, defaultValue] = args;
417
+ return isErr(result) ? defaultValue : (result.value as UnwrapOk<R>);
418
+ }
419
+
420
+ case 1: {
421
+ // Curried version: first argument is default value
422
+ const [defaultValue] = args;
423
+ return <E,>(result: Result<UnwrapOk<R>, E>) =>
424
+ unwrapOkOr(result, defaultValue);
425
+ }
426
+ }
427
+ }) as UnwrapOkOrFnOverload;
428
+
429
+ type UnwrapOkOrFnOverload = {
430
+ <R extends Base, D>(result: R, defaultValue: D): D | UnwrapOk<R>;
431
+
432
+ // Curried version
433
+ <S, D>(defaultValue: D): <E>(result: Result<S, E>) => D | S;
434
+ };
435
+
436
+ /**
437
+ * Unwraps a `Result`, returning the error value.
438
+ * Throws an error if the `Result` is `Result.Ok`.
439
+ *
440
+ * This function is used when you expect a Result to be an error and want to
441
+ * extract the error value. If the Result is unexpectedly Ok, it will throw
442
+ * an error with information about the unexpected success value.
443
+ *
444
+ * @template R The `Result.Base` type to unwrap.
445
+ * @param result The `Result` to unwrap.
446
+ * @param toStr An optional function to convert the success value to a string for the error message when the Result is unexpectedly Ok. Defaults to `String`.
447
+ * @returns The error value if `Result.Err`.
448
+ * @throws {Error} Error with message "Expected Err but got Ok: {value}" if the `Result` is `Result.Ok`.
449
+ * @example
450
+ * ```typescript
451
+ * // Basic usage - extracting error from known failure
452
+ * const failure = Result.err("Network timeout");
453
+ * console.log(Result.unwrapErrThrow(failure)); // "Network timeout"
454
+ *
455
+ * // Throws when Result is unexpectedly Ok
456
+ * const success = Result.ok(42);
457
+ * try {
458
+ * Result.unwrapErrThrow(success); // throws Error: "Expected Err but got Ok: 42"
459
+ * } catch (error) {
460
+ * console.log(error.message); // "Expected Err but got Ok: 42"
461
+ * }
462
+ *
463
+ * // Custom success value string conversion
464
+ * interface User { name: string; id: number; }
465
+ * const userResult = Result.ok<User>({ name: "John", id: 123 });
466
+ * try {
467
+ * Result.unwrapErrThrow(userResult, user => `User(${user.name}:${user.id})`);
468
+ * } catch (error) {
469
+ * console.log(error.message); // "Expected Err but got Ok: User(John:123)"
470
+ * }
471
+ *
472
+ * // In error handling contexts
473
+ * const validateAndGetError = (result: Result<any, ValidationError>) => {
474
+ * if (Result.isErr(result)) {
475
+ * return Result.unwrapErrThrow(result); // Safe to unwrap error
476
+ * }
477
+ * throw new Error("Validation unexpectedly succeeded");
478
+ * };
479
+ * ```
480
+ */
481
+ export const unwrapErrThrow = <R extends Base>(
482
+ result: R,
483
+ toStr: (v: UnwrapOk<R>) => string = toStr_,
484
+ ): UnwrapErr<R> => {
485
+ if (isOk(result)) {
486
+ throw new Error(
487
+ `Expected Err but got Ok: ${toStr(result.value as UnwrapOk<R>)}`,
488
+ );
489
+ }
490
+
491
+ return result.value as UnwrapErr<R>;
492
+ };
493
+
494
+ /**
495
+ * Unwraps a `Result`, returning the error value or `undefined` if it is `Result.Ok`.
496
+ *
497
+ * This provides a safe way to extract error values from Results without throwing
498
+ * exceptions. Useful for error handling patterns where you want to check for
499
+ * specific error conditions.
500
+ *
501
+ * @template R The `Result.Base` type to unwrap.
502
+ * @param result The `Result` to unwrap.
503
+ * @returns The error value if `Result.Err`, otherwise `undefined`.
504
+ * @example
505
+ * ```typescript
506
+ * // Basic error extraction
507
+ * const failure = Result.err("Connection failed");
508
+ * console.log(Result.unwrapErr(failure)); // "Connection failed"
509
+ *
510
+ * const success = Result.ok(42);
511
+ * console.log(Result.unwrapErr(success)); // undefined
512
+ *
513
+ * // Error handling patterns
514
+ * const handleApiCall = (result: Result<Data, ApiError>) => {
515
+ * const error = Result.unwrapErr(result);
516
+ * if (error !== undefined) {
517
+ * switch (error.type) {
518
+ * case "NETWORK_ERROR":
519
+ * return retry(result);
520
+ * case "AUTH_ERROR":
521
+ * return redirectToLogin();
522
+ * default:
523
+ * return showGenericError(error);
524
+ * }
525
+ * }
526
+ * // Handle success case...
527
+ * };
528
+ *
529
+ * // Collecting errors from multiple operations
530
+ * const results = await Promise.all([
531
+ * operation1(),
532
+ * operation2(),
533
+ * operation3()
534
+ * ]);
535
+ *
536
+ * const errors = results
537
+ * .map(Result.unwrapErr)
538
+ * .filter(err => err !== undefined); // Only actual errors
539
+ * ```
540
+ */
541
+ export const unwrapErr = <R extends Base>(
542
+ result: R,
543
+ ): UnwrapErr<R> | undefined =>
544
+ isErr(result) ? (result.value as UnwrapErr<R>) : undefined;
545
+
546
+ /**
547
+ * Unwraps a `Result`, returning the error value or a default value if it is `Result.Ok`.
548
+ * @template R The `Result.Base` type to unwrap.
549
+ * @template D The type of the default value.
550
+ * @param result The `Result` to unwrap.
551
+ * @param defaultValue The value to return if `result` is `Result.Ok`.
552
+ * @returns The error value if `Result.Err`, otherwise `defaultValue`.
553
+ * @example
554
+ * ```typescript
555
+ * // Regular usage
556
+ * const result = Result.err("failed");
557
+ * const error = Result.unwrapErrOr(result, "default");
558
+ * console.log(error); // "failed"
559
+ *
560
+ * // Curried usage for pipe composition
561
+ * const unwrapErrorWithDefault = Result.unwrapErrOr("unknown error");
562
+ * const error2 = pipe(Result.ok(42)).map(unwrapErrorWithDefault).value;
563
+ * console.log(error2); // "unknown error"
564
+ * ```
565
+ */
566
+ export const unwrapErrOr: UnwrapErrOrFnOverload = (<R extends Base, D>(
567
+ ...args: readonly [result: R, defaultValue: D] | readonly [defaultValue: D]
568
+ ):
569
+ | D
570
+ | UnwrapErr<R>
571
+ | (<S>(result: Result<S, UnwrapErr<R>>) => D | UnwrapErr<R>) => {
572
+ switch (args.length) {
573
+ case 2: {
574
+ // Direct version: first argument is result
575
+ const [result, defaultValue] = args;
576
+ return isErr(result) ? (result.value as UnwrapErr<R>) : defaultValue;
577
+ }
578
+
579
+ case 1: {
580
+ // Curried version: first argument is default value
581
+ const [defaultValue] = args;
582
+ return <S,>(result: Result<S, UnwrapErr<R>>) =>
583
+ unwrapErrOr(result, defaultValue);
584
+ }
585
+ }
586
+ }) as UnwrapErrOrFnOverload;
587
+
588
+ type UnwrapErrOrFnOverload = {
589
+ <R extends Base, D>(result: R, defaultValue: D): D | UnwrapErr<R>;
590
+
591
+ // Curried version
592
+ <E, D>(defaultValue: D): <S>(result: Result<S, E>) => D | E;
593
+ };
594
+
595
+ /**
596
+ * Maps a `Result<S, E>` to `Result<S2, E>` by applying a function to the success value.
597
+ * If the `Result` is `Result.Err`, returns the original `Err`.
598
+ * @template R The input `Result.Base` type.
599
+ * @template S2 The type of the success value returned by the mapping function.
600
+ * @param result The `Result` to map.
601
+ * @param mapFn The function to apply to the success value if present.
602
+ * @returns A new `Result<S2, UnwrapErr<R>>`.
603
+ * @example
604
+ * ```typescript
605
+ * // Regular usage
606
+ * const result = Result.ok(5);
607
+ * const mapped = Result.map(result, x => x * 2);
608
+ * console.log(Result.unwrap(mapped)); // 10
609
+ *
610
+ * // Curried version for use with pipe
611
+ * const doubler = Result.map((x: number) => x * 2);
612
+ * const result2 = pipe(Result.ok(5)).map(doubler).value;
613
+ * console.log(Result.unwrap(result2)); // 10
614
+ * ```
615
+ */
616
+ export const map: MapFnOverload = (<R extends Base, S2>(
617
+ ...args:
618
+ | readonly [result: R, mapFn: (value: UnwrapOk<R>) => S2]
619
+ | readonly [mapFn: (value: UnwrapOk<R>) => S2]
620
+ ): Result<S2, UnwrapErr<R>> | ((result: R) => Result<S2, UnwrapErr<R>>) => {
621
+ switch (args.length) {
622
+ case 2: {
623
+ const [result, mapFn] = args;
624
+ return isErr(result)
625
+ ? (result as Err<UnwrapErr<R>>)
626
+ : ok(mapFn(result.value as UnwrapOk<R>));
627
+ }
628
+
629
+ case 1: {
630
+ // Curried version: first argument is mapping function
631
+ const [mapFn] = args;
632
+ return (result: R) => map(result, mapFn);
633
+ }
634
+ }
635
+ }) as MapFnOverload;
636
+
637
+ type MapFnOverload = {
638
+ <R extends Base, S2>(
639
+ result: R,
640
+ mapFn: (value: UnwrapOk<R>) => S2,
641
+ ): Result<S2, UnwrapErr<R>>;
642
+
643
+ // Curried version
644
+ <S, S2>(
645
+ mapFn: (value: S) => S2,
646
+ ): <E>(result: Result<S, E>) => Result<S2, E>;
647
+ };
648
+
649
+ /**
650
+ * Maps a `Result<S, E>` to `Result<S, E2>` by applying a function to the error value.
651
+ * If the `Result` is `Result.Ok`, returns the original `Ok`.
652
+ * @template R The input `Result.Base` type.
653
+ * @template E2 The type of the error value returned by the mapping function.
654
+ * @param result The `Result` to map.
655
+ * @param mapFn The function to apply to the error value if present.
656
+ * @returns A new `Result<UnwrapOk<R>, E2>`.
657
+ * @example
658
+ * ```typescript
659
+ * // Regular usage
660
+ * const result = Result.err("error");
661
+ * const mapped = Result.mapErr(result, e => e.toUpperCase());
662
+ * console.log(Result.unwrapErr(mapped)); // "ERROR"
663
+ *
664
+ * // Curried usage for pipe composition
665
+ * const errorUppercase = Result.mapErr((e: string) => e.toUpperCase());
666
+ * const result2 = pipe(Result.err("error")).map(errorUppercase).value;
667
+ * console.log(Result.unwrapErr(result2)); // "ERROR"
668
+ * ```
669
+ */
670
+ export const mapErr: MapErrFnOverload = (<R extends Base, E2>(
671
+ ...args:
672
+ | readonly [result: R, mapFn: (error: UnwrapErr<R>) => E2]
673
+ | readonly [mapFn: (error: UnwrapErr<R>) => E2]
674
+ ): Result<UnwrapOk<R>, E2> | ((result: R) => Result<UnwrapOk<R>, E2>) => {
675
+ switch (args.length) {
676
+ case 2: {
677
+ const [result, mapFn] = args;
678
+ return isOk(result)
679
+ ? (result as Ok<UnwrapOk<R>>)
680
+ : err(mapFn(result.value as UnwrapErr<R>));
681
+ }
682
+
683
+ case 1: {
684
+ // Curried version: first argument is mapping function
685
+ const [mapFn] = args;
686
+ return (result: R) => mapErr(result, mapFn);
687
+ }
688
+ }
689
+ }) as MapErrFnOverload;
690
+
691
+ type MapErrFnOverload = {
692
+ <R extends Base, E2>(
693
+ result: R,
694
+ mapFn: (error: UnwrapErr<R>) => E2,
695
+ ): Result<UnwrapOk<R>, E2>;
696
+
697
+ // Curried version
698
+ <E, E2>(
699
+ mapFn: (error: E) => E2,
700
+ ): <S>(result: Result<S, E>) => Result<S, E2>;
701
+ };
702
+
703
+ /**
704
+ * Applies one of two functions depending on whether the `Result` is `Ok` or `Err`.
705
+ * @template R The input `Result.Base` type.
706
+ * @template S2 The type of the success value returned by `mapFn`.
707
+ * @template E2 The type of the error value returned by `mapErrFn`.
708
+ * @param result The `Result` to fold.
709
+ * @param mapFn The function to apply if `result` is `Ok`.
710
+ * @param mapErrFn The function to apply if `result` is `Err`.
711
+ * @returns A new `Result<S2, E2>` based on the applied function.
712
+ * @example
713
+ * ```typescript
714
+ * // Regular usage
715
+ * const result = Result.ok(42);
716
+ * const folded = Result.fold(result, x => x * 2, () => 0);
717
+ * console.log(Result.unwrapOk(folded)); // 84
718
+ *
719
+ * // Curried usage for pipe composition
720
+ * const folder = Result.fold((x: number) => x * 2, () => 0);
721
+ * const result2 = pipe(Result.ok(42)).map(folder).value;
722
+ * console.log(Result.unwrapOk(result2)); // 84
723
+ * ```
724
+ */
725
+ export const fold: FoldFnOverload = (<R extends Base, S2, E2>(
726
+ ...args:
727
+ | readonly [
728
+ result: R,
729
+ mapFn: (value: UnwrapOk<R>) => S2,
730
+ mapErrFn: (error: UnwrapErr<R>) => E2,
731
+ ]
732
+ | readonly [
733
+ mapFn: (value: UnwrapOk<R>) => S2,
734
+ mapErrFn: (error: UnwrapErr<R>) => E2,
735
+ ]
736
+ ):
737
+ | Result<S2, E2>
738
+ | ((result: Result<UnwrapOk<R>, UnwrapErr<R>>) => Result<S2, E2>) => {
739
+ switch (args.length) {
740
+ case 3: {
741
+ const [result, mapFn, mapErrFn] = args;
742
+ return isOk(result)
743
+ ? ok(mapFn(result.value as UnwrapOk<R>))
744
+ : err(mapErrFn(result.value as UnwrapErr<R>));
745
+ }
746
+
747
+ case 2: {
748
+ const [mapFn, mapErrFn] = args;
749
+ return (result: Result<UnwrapOk<R>, UnwrapErr<R>>) =>
750
+ isOk(result) ? ok(mapFn(result.value)) : err(mapErrFn(result.value));
751
+ }
752
+ }
753
+ }) as FoldFnOverload;
754
+
755
+ type FoldFnOverload = {
756
+ <R extends Base, S2, E2>(
757
+ result: R,
758
+ mapFn: (value: UnwrapOk<R>) => S2,
759
+ mapErrFn: (error: UnwrapErr<R>) => E2,
760
+ ): Result<S2, E2>;
761
+
762
+ // Curried version
763
+ <S, E, S2, E2>(
764
+ mapFn: (value: S) => S2,
765
+ mapErrFn: (error: E) => E2,
766
+ ): (result: Result<S, E>) => Result<S2, E2>;
767
+ };
768
+
769
+ /**
770
+ * Applies a function that returns a `Result` to the success value of a `Result`.
771
+ * If the input is `Err`, returns the original `Err`.
772
+ * This is the monadic bind operation for `Result`.
773
+ * @template R The input `Result.Base` type.
774
+ * @template S2 The success type of the `Result` returned by the function.
775
+ * @template E2 The error type of the `Result` returned by the function.
776
+ * @param result The `Result` to flat map.
777
+ * @param flatMapFn The function to apply that returns a `Result`.
778
+ * @returns The result of applying the function, or the original `Err`.
779
+ * @example
780
+ * ```typescript
781
+ * // Regular usage
782
+ * const divide = (a: number, b: number): Result<number, string> =>
783
+ * b === 0 ? Result.err("Division by zero") : Result.ok(a / b);
784
+ *
785
+ * const result = Result.flatMap(Result.ok(10), x => divide(x, 2));
786
+ * console.log(Result.unwrapOk(result)); // 5
787
+ *
788
+ * // Curried usage for pipe composition
789
+ * const divideBy2 = Result.flatMap((x: number) => divide(x, 2));
790
+ * const result2 = pipe(Result.ok(10)).map(divideBy2).value;
791
+ * console.log(Result.unwrapOk(result2)); // 5
792
+ * ```
793
+ */
794
+ export const flatMap: FlatMapFnOverload = (<R extends Base, S2, E2>(
795
+ ...args:
796
+ | readonly [result: R, flatMapFn: (value: UnwrapOk<R>) => Result<S2, E2>]
797
+ | readonly [flatMapFn: (value: UnwrapOk<R>) => Result<S2, E2>]
798
+ ):
799
+ | Result<S2, E2 | UnwrapErr<R>>
800
+ | (<E>(result: Result<UnwrapOk<R>, E>) => Result<S2, E | E2>) => {
801
+ switch (args.length) {
802
+ case 2: {
803
+ const [result, flatMapFn] = args;
804
+ return isErr(result)
805
+ ? (result as Err<UnwrapErr<R>>)
806
+ : flatMapFn(result.value as UnwrapOk<R>);
807
+ }
808
+
809
+ case 1: {
810
+ const [flatMapFn] = args;
811
+ return <E,>(result: Result<UnwrapOk<R>, E>) =>
812
+ isErr(result) ? result : flatMapFn(result.value);
813
+ }
814
+ }
815
+ }) as FlatMapFnOverload;
816
+
817
+ type FlatMapFnOverload = {
818
+ <R extends Base, S2, E2>(
819
+ result: R,
820
+ flatMapFn: (value: UnwrapOk<R>) => Result<S2, E2>,
821
+ ): Result<S2, E2 | UnwrapErr<R>>;
822
+
823
+ // Curried version
824
+ <S, S2, E2>(
825
+ flatMapFn: (value: S) => Result<S2, E2>,
826
+ ): <E>(result: Result<S, E>) => Result<S2, E | E2>;
827
+ };
828
+
829
+ /**
830
+ * Unwraps a `Result`, returning the success value or throwing an error with the provided message.
831
+ * @template R The `Result.Base` type to unwrap.
832
+ * @param result The `Result` to unwrap.
833
+ * @param message The error message to throw if the `Result` is `Result.Err`.
834
+ * @returns The success value if `Result.Ok`.
835
+ * @throws Error with the provided message if the `Result` is `Result.Err`.
836
+ * @example
837
+ * ```typescript
838
+ * // Regular usage
839
+ * const result = Result.ok(42);
840
+ * const value = Result.expectToBe(result, "Operation must succeed");
841
+ * console.log(value); // 42
842
+ *
843
+ * // Curried usage for pipe composition
844
+ * const mustBeOk = Result.expectToBe("Operation must succeed");
845
+ * const value2 = pipe(Result.ok(42)).map(mustBeOk).value;
846
+ * console.log(value2); // 42
847
+ * ```
848
+ */
849
+ export const expectToBe: ExpectToBeFnOverload = (<R extends Base>(
850
+ ...args: readonly [result: R, message: string] | readonly [message: string]
851
+ ): UnwrapOk<R> | (<E>(result: Result<UnwrapOk<R>, E>) => UnwrapOk<R>) => {
852
+ switch (args.length) {
853
+ case 2: {
854
+ // Direct version: first argument is result
855
+ const [result, message] = args;
856
+ if (isOk(result)) {
857
+ return unwrapOk(result);
858
+ }
859
+
860
+ throw new Error(message);
861
+ }
862
+
863
+ case 1: {
864
+ // Curried version: first argument is message
865
+ const [message] = args;
866
+ return <E,>(result: Result<UnwrapOk<R>, E>): UnwrapOk<R> =>
867
+ expectToBe(result, message);
868
+ }
869
+ }
870
+ }) as ExpectToBeFnOverload;
871
+
872
+ type ExpectToBeFnOverload = {
873
+ <R extends Base>(result: R, message: string): UnwrapOk<R>;
874
+
875
+ // Curried version
876
+ <S>(message: string): <E>(result: Result<S, E>) => S;
877
+ };
878
+
879
+ /**
880
+ * @internal
881
+ * Utility type to extract the resolved value type from a Promise.
882
+ * @template P The Promise type.
883
+ * @example
884
+ * UnwrapPromise<Promise<string>> // string
885
+ * UnwrapPromise<Promise<number>> // number
886
+ */
887
+ type UnwrapPromise<P extends Promise<unknown>> =
888
+ P extends Promise<infer V> ? V : never;
889
+
890
+ /**
891
+ * Converts a Promise into a Promise that resolves to a `Result`.
892
+ * If the input Promise resolves, the `Result` will be `Ok` with the resolved value.
893
+ * If the input Promise rejects, the `Result` will be `Err` with the rejection reason.
894
+ * @template P The type of the input Promise.
895
+ * @param promise The Promise to convert.
896
+ * @returns A Promise that resolves to `Result<UnwrapPromise<P>, unknown>`.
897
+ */
898
+ export const fromPromise = <P extends Promise<unknown>>(
899
+ promise: P,
900
+ ): Promise<Result<UnwrapPromise<P>, unknown>> =>
901
+ promise.then((v) => ok(v) as Ok<UnwrapPromise<P>>).catch(err);
902
+
903
+ /**
904
+ * Wraps a function that may throw an exception in a `Result`.
905
+ *
906
+ * This is a fundamental utility for converting traditional exception-based error
907
+ * handling into Result-based error handling. Any thrown value is converted to an
908
+ * Error object for consistent error handling.
909
+ *
910
+ * If the function executes successfully, returns `Result.Ok` with the result.
911
+ * If the function throws, returns `Result.Err` with the caught error.
912
+ *
913
+ * @template T The return type of the function.
914
+ * @param fn The function to execute that may throw.
915
+ * @returns A `Result<T, Error>` containing either the successful result or the caught error.
916
+ * @example
917
+ * ```typescript
918
+ * // Wrapping JSON.parse which can throw
919
+ * const parseJson = <T>(text: string): Result<T, Error> =>
920
+ * Result.fromThrowable(() => JSON.parse(text) as T);
921
+ *
922
+ * const validJson = parseJson<{valid: boolean}>('{"valid": true}');
923
+ * if (Result.isOk(validJson)) {
924
+ * console.log(validJson.value.valid); // true
925
+ * }
926
+ *
927
+ * const invalidJson = parseJson('{invalid json}');
928
+ * if (Result.isErr(invalidJson)) {
929
+ * console.log(invalidJson.value.message); // SyntaxError message
930
+ * }
931
+ *
932
+ * // Using with custom validation
933
+ * const parsePositiveNumber = (str: string): Result<number, Error> =>
934
+ * Result.fromThrowable(() => {
935
+ * const num = Number(str);
936
+ * if (Number.isNaN(num)) throw new Error(`Not a number: ${str}`);
937
+ * if (num <= 0) throw new Error(`Must be positive: ${num}`);
938
+ * return num;
939
+ * });
940
+ *
941
+ * const success = parsePositiveNumber('42');
942
+ * console.log(Result.unwrapOkOr(success, 0)); // 42
943
+ *
944
+ * const failure = parsePositiveNumber('abc');
945
+ * console.log(Result.unwrapOkOr(failure, 0)); // 0
946
+ *
947
+ * // Wrapping DOM operations that might fail
948
+ * const getElementText = (id: string): Result<string, Error> =>
949
+ * Result.fromThrowable(() => {
950
+ * const element = document.getElementById(id);
951
+ * if (!element) throw new Error(`Element not found: ${id}`);
952
+ * return element.textContent || "";
953
+ * });
954
+ *
955
+ * // Wrapping file operations
956
+ * const readFileSync = (path: string): Result<string, Error> =>
957
+ * Result.fromThrowable(() =>
958
+ * require('fs').readFileSync(path, 'utf8')
959
+ * );
960
+ * ```
961
+ */
962
+ export const fromThrowable = <T,>(fn: () => T): Result<T, Error> => {
963
+ try {
964
+ return ok(fn());
965
+ } catch (error) {
966
+ if (error instanceof Error) {
967
+ return err(error);
968
+ }
969
+ const msg = unknownToString(error);
970
+ if (isErr(msg)) {
971
+ return err(new Error(String(error)));
972
+ } else {
973
+ return err(new Error(msg.value));
974
+ }
975
+ }
976
+ };
977
+
978
+ /**
979
+ * Swaps the success and error values of a `Result`.
980
+ * @template R The input `Result.Base` type.
981
+ * @param result The `Result` to swap.
982
+ * @returns A new `Result` with success and error swapped.
983
+ * @example
984
+ * ```typescript
985
+ * const okResult = Result.ok(42);
986
+ * const swapped = Result.swap(okResult);
987
+ * console.log(Result.isErr(swapped)); // true
988
+ * console.log(Result.unwrapErr(swapped)); // 42
989
+ * ```
990
+ */
991
+ export const swap = <R extends Base>(
992
+ result: R,
993
+ ): Result<UnwrapErr<R>, UnwrapOk<R>> =>
994
+ isOk(result) ? err(unwrapOk(result)) : ok(result.value as UnwrapErr<R>);
995
+
996
+ /**
997
+ * Converts a `Result` to an `Optional`.
998
+ *
999
+ * This conversion is useful when you want to discard error information and only
1000
+ * care about whether an operation succeeded. The error information is lost in
1001
+ * this conversion, so use it when error details are not needed.
1002
+ *
1003
+ * If the `Result` is `Ok`, returns `Some` with the value.
1004
+ * If the `Result` is `Err`, returns `None`.
1005
+ *
1006
+ * @template R The input `Result.Base` type.
1007
+ * @param result The `Result` to convert.
1008
+ * @returns An `Optional<UnwrapOk<R>>` containing the success value or representing `None`.
1009
+ * @example
1010
+ * ```typescript
1011
+ * // Basic conversion
1012
+ * const okResult = Result.ok(42);
1013
+ * const optional = Result.toOptional(okResult);
1014
+ * console.log(Optional.isSome(optional)); // true
1015
+ * console.log(Optional.unwrap(optional)); // 42
1016
+ *
1017
+ * const errResult = Result.err("Network error");
1018
+ * const none = Result.toOptional(errResult);
1019
+ * console.log(Optional.isNone(none)); // true
1020
+ *
1021
+ * // Use case: when you only care about success, not error details
1022
+ * const fetchUserName = (id: number): Result<string, ApiError> => {
1023
+ * // ... implementation
1024
+ * };
1025
+ *
1026
+ * const maybeUserName = Result.toOptional(fetchUserName(123));
1027
+ * const displayName = Optional.unwrapOr(maybeUserName, "Unknown User");
1028
+ *
1029
+ * // Converting multiple Results and filtering successes
1030
+ * const userIds = [1, 2, 3, 4];
1031
+ * const userNames = userIds
1032
+ * .map(fetchUserName)
1033
+ * .map(Result.toOptional)
1034
+ * .filter(Optional.isSome)
1035
+ * .map(Optional.unwrap); // string[]
1036
+ *
1037
+ * // Chaining with Optional operations
1038
+ * const processResult = (r: Result<string, Error>) =>
1039
+ * pipe(Result.toOptional(r))
1040
+ * .map(Optional.map(s => s.toUpperCase()))
1041
+ * .map(Optional.filter(s => s.length > 0))
1042
+ * .value;
1043
+ * ```
1044
+ */
1045
+ export const toOptional = <R extends Base>(
1046
+ result: R,
1047
+ ): Optional<UnwrapOk<R>> =>
1048
+ isOk(result) ? Optional.some(unwrapOk(result)) : Optional.none;
1049
+
1050
+ /**
1051
+ * Returns the `Result` if it is `Ok`, otherwise returns the alternative.
1052
+ * @template R The input `Result.Base` type.
1053
+ * @param result The `Result` to check.
1054
+ * @param alternative The alternative `Result` to return if the first is `Err`.
1055
+ * @returns The first `Result` if `Ok`, otherwise the alternative.
1056
+ * @example
1057
+ * ```typescript
1058
+ * // Regular usage
1059
+ * const primary = Result.err("error");
1060
+ * const fallback = Result.ok("default");
1061
+ * const result = Result.orElse(primary, fallback);
1062
+ * console.log(Result.unwrapOk(result)); // "default"
1063
+ *
1064
+ * // Curried usage for pipe composition
1065
+ * const fallbackTo = Result.orElse(Result.ok("fallback"));
1066
+ * const result2 = pipe(Result.err("error")).map(fallbackTo).value;
1067
+ * console.log(Result.unwrapOk(result2)); // "fallback"
1068
+ * ```
1069
+ */
1070
+ export const orElse: OrElseFnOverload = (<R extends Base, R2 extends Base>(
1071
+ ...args: readonly [result: R, alternative: R2] | readonly [alternative: R2]
1072
+ ):
1073
+ | (NarrowToOk<R> | R2)
1074
+ | ((
1075
+ result: Result<UnwrapOk<R>, UnwrapErr<R>>,
1076
+ ) => Result<UnwrapOk<R>, UnwrapErr<R>> | R2) => {
1077
+ switch (args.length) {
1078
+ case 2: {
1079
+ const [result, alternative] = args;
1080
+ return isOk(result) ? result : alternative;
1081
+ }
1082
+
1083
+ case 1: {
1084
+ // Curried version: one argument (alternative) provided
1085
+ const [alternative] = args;
1086
+ return (result: Result<UnwrapOk<R>, UnwrapErr<R>>) =>
1087
+ orElse(result, alternative);
1088
+ }
1089
+ }
1090
+ }) as OrElseFnOverload;
1091
+
1092
+ type OrElseFnOverload = {
1093
+ <R extends Base, R2 extends Base>(
1094
+ result: R,
1095
+ alternative: R2,
1096
+ ): NarrowToOk<R> | R2;
1097
+
1098
+ // Curried version
1099
+ <S, E, S2, E2>(
1100
+ alternative: Result<S2, E2>,
1101
+ ): (result: Result<S, E>) => Result<S, E> | Result<S2, E2>;
1102
+ };
1103
+
1104
+ /**
1105
+ * Combines two `Result` values into a single `Result` containing a tuple.
1106
+ * If either `Result` is `Err`, returns the first `Err` encountered.
1107
+ * @template S1 The success type of the first `Result`.
1108
+ * @template E1 The error type of the first `Result`.
1109
+ * @template S2 The success type of the second `Result`.
1110
+ * @template E2 The error type of the second `Result`.
1111
+ * @param resultA The first `Result`.
1112
+ * @param resultB The second `Result`.
1113
+ * @returns A `Result` containing a tuple of both values, or the first `Err`.
1114
+ * @example
1115
+ * ```typescript
1116
+ * const a = Result.ok(1);
1117
+ * const b = Result.ok("hello");
1118
+ * const zipped = Result.zip(a, b);
1119
+ * console.log(Result.unwrapOk(zipped)); // [1, "hello"]
1120
+ *
1121
+ * const withErr = Result.zip(a, Result.err("error"));
1122
+ * console.log(Result.unwrapErr(withErr)); // "error"
1123
+ * ```
1124
+ */
1125
+ export const zip = <S1, E1, S2, E2>(
1126
+ resultA: Result<S1, E1>,
1127
+ resultB: Result<S2, E2>,
1128
+ ): Result<readonly [S1, S2], E1 | E2> =>
1129
+ isOk(resultA)
1130
+ ? isOk(resultB)
1131
+ ? ok([resultA.value, resultB.value] as const)
1132
+ : resultB
1133
+ : resultA;
1134
+ }