@mark1russell7/collections 0.6.0 → 0.7.1

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.
@@ -1,327 +0,0 @@
1
- /**
2
- * Functional effect types for error handling and optional values.
3
- *
4
- * This module gives Option<T> and Result<T,E> types for explicit, type-safe
5
- * error handling without exceptions. This module includes async variants.
6
- */
7
-
8
- // ============================================================================
9
- // Option<T> - represents optional values
10
- // ============================================================================
11
-
12
- /**
13
- * This type represents the absence of a value.
14
- */
15
- export interface None {
16
- readonly _tag: "None";
17
- }
18
-
19
- /**
20
- * This type represents the presence of a value.
21
- */
22
- export interface Some<T> {
23
- readonly _tag: "Some";
24
- readonly value: T;
25
- }
26
-
27
- /**
28
- * Option<T> represents a value that is present or absent.
29
- * This is a type-safe alternative to null/undefined.
30
- *
31
- * @example
32
- * function findUser(id: string): Option<User> {
33
- * const user = db.get(id);
34
- * return user ? Some(user) : None;
35
- * }
36
- */
37
- export type Option<T> = None | Some<T>;
38
-
39
- /**
40
- * The singleton None value.
41
- */
42
- export const None: None = Object.freeze({ _tag: "None" });
43
-
44
- /**
45
- * This function constructs a Some value containing the given value.
46
- */
47
- export const Some = <T>(value: T): Some<T> =>
48
- Object.freeze({ _tag: "Some", value });
49
-
50
- /**
51
- * Type guard to check if an Option is None.
52
- */
53
- export const isNone = <T>(opt: Option<T>): opt is None => opt._tag === "None";
54
-
55
- /**
56
- * Type guard to check if an Option is Some.
57
- */
58
- export const isSome = <T>(opt: Option<T>): opt is Some<T> =>
59
- opt._tag === "Some";
60
-
61
- /**
62
- * This function extracts the value from a Some, or gives the default value if None.
63
- */
64
- export const getOrElse = <T>(opt: Option<T>, defaultValue: T): T =>
65
- isSome(opt) ? opt.value : defaultValue;
66
-
67
- /**
68
- * This function extracts the value from a Some, or throws an error if None.
69
- */
70
- export const unwrap = <T>(opt: Option<T>): T => {
71
- if (isSome(opt)) return opt.value;
72
- throw new Error("Called unwrap on None");
73
- };
74
-
75
- /**
76
- * This function maps a function over the value in a Some, or gives None.
77
- */
78
- export const mapOption = <T, U>(
79
- opt: Option<T>,
80
- f: (value: T) => U
81
- ): Option<U> => (isSome(opt) ? Some(f(opt.value)) : None);
82
-
83
- /**
84
- * Chains Option-returning operations.
85
- */
86
- export const flatMapOption = <T, U>(
87
- opt: Option<T>,
88
- f: (value: T) => Option<U>
89
- ): Option<U> => (isSome(opt) ? f(opt.value) : None);
90
-
91
- /**
92
- * This function converts a nullable value to an Option.
93
- */
94
- export const fromNullable = <T>(value: T | null | undefined): Option<T> =>
95
- value == null ? None : Some(value);
96
-
97
- /**
98
- * This function converts an Option to a nullable value.
99
- */
100
- export const toNullable = <T>(opt: Option<T>): T | undefined =>
101
- isSome(opt) ? opt.value : undefined;
102
-
103
- // ============================================================================
104
- // Result<T, E> - represents success or failure
105
- // ============================================================================
106
-
107
- /**
108
- * This type represents a successful result containing a value.
109
- */
110
- export interface Ok<T> {
111
- readonly _tag: "Ok";
112
- readonly value: T;
113
- /** This method calls the `Ok` case with the value. */
114
- match<U>(cases: { Ok: (value: T) => U; Err: (error: never) => U }): U;
115
- }
116
-
117
- /**
118
- * This type represents a failed result containing an error.
119
- */
120
- export interface Err<E> {
121
- readonly _tag: "Err";
122
- readonly error: E;
123
- /** This method calls the `Err` case with the error. */
124
- match<U>(cases: { Ok: (value: never) => U; Err: (error: E) => U }): U;
125
- }
126
-
127
- /**
128
- * Result<T, E> represents the result of an operation that can fail.
129
- * It contains either a success value (Ok) or an error value (Err).
130
- *
131
- * @example
132
- * function divide(a: number, b: number): Result<number, string> {
133
- * if (b === 0) return Err("Division by zero");
134
- * return Ok(a / b);
135
- * }
136
- */
137
- export type Result<T, E> = Ok<T> | Err<E>;
138
-
139
- /**
140
- * This function constructs an Ok result containing the given value.
141
- */
142
- export const Ok = <T>(value: T): Ok<T> =>
143
- Object.freeze({
144
- _tag: "Ok",
145
- value,
146
- match: <U>(f: { Ok: (value: T) => U; Err: (error: unknown) => U }) =>
147
- f.Ok(value),
148
- });
149
-
150
- /**
151
- * This function constructs an Err result containing the given error.
152
- */
153
- export const Err = <E>(error: E): Err<E> =>
154
- Object.freeze({
155
- _tag: "Err",
156
- error,
157
- match: <U>(f: { Ok: (value: unknown) => U; Err: (error: E) => U }) =>
158
- f.Err(error),
159
- });
160
-
161
- /**
162
- * Type guard to check if a Result is Ok.
163
- */
164
- export const isOk = <T, E>(result: Result<T, E>): result is Ok<T> =>
165
- result._tag === "Ok";
166
-
167
- /**
168
- * Type guard to check if a Result is Err.
169
- */
170
- export const isErr = <T, E>(result: Result<T, E>): result is Err<E> =>
171
- result._tag === "Err";
172
-
173
- /**
174
- * This function extracts the value from an Ok, or gives the default value if Err.
175
- */
176
- export const getOrElseResult = <T, E>(
177
- result: Result<T, E>,
178
- defaultValue: T
179
- ): T => (isOk(result) ? result.value : defaultValue);
180
-
181
- /**
182
- * This function extracts the value from an Ok, or throws the error if Err.
183
- */
184
- export const unwrapResult = <T, E>(result: Result<T, E>): T => {
185
- if (isOk(result)) return result.value;
186
- throw result.error;
187
- };
188
-
189
- /**
190
- * This function maps a function over the value in an Ok, or gives the Err unchanged.
191
- */
192
- export const mapResult = <T, U, E>(
193
- result: Result<T, E>,
194
- f: (value: T) => U
195
- ): Result<U, E> => (isOk(result) ? Ok(f(result.value)) : result);
196
-
197
- /**
198
- * This function maps a function over the error in an Err, or gives the Ok unchanged.
199
- */
200
- export const mapError = <T, E, F>(
201
- result: Result<T, E>,
202
- f: (error: E) => F
203
- ): Result<T, F> => (isErr(result) ? Err(f(result.error)) : result);
204
-
205
- /**
206
- * Chains Result-returning operations.
207
- */
208
- export const flatMapResult = <T, U, E>(
209
- result: Result<T, E>,
210
- f: (value: T) => Result<U, E>
211
- ): Result<U, E> => (isOk(result) ? f(result.value) : result);
212
-
213
- /**
214
- * This function converts a throwing function into a Result-returning function.
215
- */
216
- export const tryCatch = <T, E = unknown>(
217
- fn: () => T,
218
- onError?: (error: unknown) => E
219
- ): Result<T, E> => {
220
- try {
221
- return Ok(fn());
222
- } catch (error) {
223
- return Err((onError ? onError(error) : error) as E);
224
- }
225
- };
226
-
227
- /**
228
- * This function converts an async throwing function into a Result-returning async function.
229
- */
230
- export const tryCatchAsync = async <T, E = unknown>(
231
- fn: () => Promise<T>,
232
- onError?: (error: unknown) => E
233
- ): Promise<Result<T, E>> => {
234
- try {
235
- return Ok(await fn());
236
- } catch (error) {
237
- return Err((onError ? onError(error) : error) as E);
238
- }
239
- };
240
-
241
- // ============================================================================
242
- // Async variants
243
- // ============================================================================
244
-
245
- /**
246
- * Async variant of Option<T>.
247
- */
248
- export type AsyncOption<T> = Promise<Option<T>>;
249
-
250
- /**
251
- * Async variant of Result<T, E>.
252
- */
253
- export type AsyncResult<T, E> = Promise<Result<T, E>>;
254
-
255
- /**
256
- * This function maps a function over an async Option.
257
- */
258
- export const mapAsyncOption = async <T, U>(
259
- opt: AsyncOption<T>,
260
- f: (value: T) => U | Promise<U>
261
- ): AsyncOption<U> => {
262
- const resolved = await opt;
263
- if (isSome(resolved)) {
264
- return Some(await f(resolved.value));
265
- }
266
- return None;
267
- };
268
-
269
- /**
270
- * This function maps a function over an async Result.
271
- */
272
- export const mapAsyncResult = async <T, U, E>(
273
- result: AsyncResult<T, E>,
274
- f: (value: T) => U | Promise<U>
275
- ): AsyncResult<U, E> => {
276
- const resolved = await result;
277
- if (isOk(resolved)) {
278
- return Ok(await f(resolved.value));
279
- }
280
- return resolved;
281
- };
282
-
283
- // ============================================================================
284
- // Conversion utilities
285
- // ============================================================================
286
-
287
- /**
288
- * This function converts an Option to a Result.
289
- * None becomes Err with the given error.
290
- */
291
- export const optionToResult = <T, E>(opt: Option<T>, error: E): Result<T, E> =>
292
- isSome(opt) ? Ok(opt.value) : Err(error);
293
-
294
- /**
295
- * This function converts a Result to an Option.
296
- * Err becomes None, discarding the error.
297
- */
298
- export const resultToOption = <T, E>(result: Result<T, E>): Option<T> =>
299
- isOk(result) ? Some(result.value) : None;
300
-
301
- /**
302
- * This function combines multiple Options into an Option of an array.
303
- * This function gives None if any input is None.
304
- */
305
- export const sequence = <T>(opts: Option<T>[]): Option<T[]> => {
306
- const values: T[] = [];
307
- for (const opt of opts) {
308
- if (isNone(opt)) return None;
309
- values.push(opt.value);
310
- }
311
- return Some(values);
312
- };
313
-
314
- /**
315
- * This function combines multiple Results into a Result of an array.
316
- * This function gives the first Err encountered, or Ok with all values.
317
- */
318
- export const sequenceResults = <T, E>(
319
- results: Result<T, E>[]
320
- ): Result<T[], E> => {
321
- const values: T[] = [];
322
- for (const result of results) {
323
- if (isErr(result)) return result;
324
- values.push(result.value);
325
- }
326
- return Ok(values);
327
- };