rsult 1.3.0 → 2.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.
package/src/option.ts CHANGED
@@ -1,273 +1,279 @@
1
- export type Option<T> =
2
- OptionSome<T> | OptionNone<T>;
1
+ // ============================================================================
2
+ // Type-Level Utilities
3
+ // ============================================================================
4
+
5
+ /** Unique brand symbols for nominal typing */
6
+ declare const SomeBrand: unique symbol;
7
+ declare const NoneBrand: unique symbol;
8
+
9
+ /** Extract the inner type from an Option */
10
+ export type UnwrapOption<O> = O extends Option<infer T> ? T : never;
11
+
12
+ /** Unwrap nested Option types for flatten() */
13
+ export type FlattenOption<T> = T extends Option<infer U> ? Option<U> : Option<T>;
14
+
15
+ /** Type-level check for nested Options */
16
+ export type IsNestedOption<T> = T extends Option<any> ? true : false;
17
+
18
+ // ============================================================================
19
+ // Option Type Definition
20
+ // ============================================================================
21
+
22
+ /**
23
+ * A discriminated union representing an optional value.
24
+ *
25
+ * An `Option<T>` is either `Some(T)` containing a value, or `None` representing absence.
26
+ *
27
+ * @typeParam T - The type of the contained value
28
+ */
29
+ export type Option<T> = OptionSome<T> | OptionNone<T>;
30
+
31
+ // ============================================================================
32
+ // Core Interfaces
33
+ // ============================================================================
3
34
 
4
35
  export interface IOptionCheck<T> {
5
36
  /**
6
- * Determines if the Option is Some.
7
- * @returns true if the Option is Some, otherwise false.
37
+ * Returns `true` if the option is `Some`.
8
38
  *
9
- * Usage Example:
10
- * const myOption = Some(5);
11
- * if (myOption.is_some()) {
12
- * console.log("It's Some!");
13
- * }
39
+ * This is a type guard that narrows the type to `OptionSome<T>`.
14
40
  */
15
41
  is_some(): this is OptionSome<T>;
16
42
 
17
43
  /**
18
- * Determines if the Option is Some and the contained value meets a condition.
19
- * @param f The condition to apply to the contained value if it's Some.
20
- * @returns true if the Option is Some and the condition returns true, otherwise false.
21
- *
22
- * Usage Example:
23
- * const myOption = Some(5);
24
- * const isGreaterThanThree = myOption.is_some_and(x => x > 3); // true
44
+ * Returns `true` if `Some` and the value satisfies the predicate.
25
45
  */
26
46
  is_some_and(f: (arg: T) => boolean): boolean;
27
47
 
28
48
  /**
29
- * Determines if the Option is None.
30
- * @returns true if the Option is None, otherwise false.
49
+ * Returns `true` if the option is `None`.
31
50
  *
32
- * Usage Example:
33
- * const myOption = None();
34
- * if (myOption.is_none()) {
35
- * console.log("It's None!");
36
- * }
51
+ * This is a type guard that narrows the type to `OptionNone<T>`.
37
52
  */
38
- is_none(): boolean;
53
+ is_none(): this is OptionNone<T>;
54
+
55
+ /**
56
+ * Returns `true` if `None` OR if the value satisfies the predicate.
57
+ *
58
+ * This is the logical complement of `is_some_and` with negated predicate.
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * Some(2).is_none_or(x => x > 1) // true
63
+ * Some(0).is_none_or(x => x > 1) // false
64
+ * None().is_none_or(x => x > 1) // true
65
+ * ```
66
+ */
67
+ is_none_or(f: (arg: T) => boolean): boolean;
39
68
  }
40
69
 
41
70
  export interface IOptionExpect<T> {
42
71
  /**
43
- * Extracts the value from a Some, throwing an error if it is None.
44
- * @param msg The error message to throw if the Option is None.
45
- * @returns The contained value if the Option is Some.
46
- * @throws Error with provided message if the Option is None.
72
+ * Returns the contained `Some` value, or throws with the provided message.
47
73
  *
48
- * Usage Example:
49
- * const myOption = Some(5);
50
- * const value = myOption.expect("Expected a value!"); // 5
74
+ * @throws Error with `msg` if this is `None`
51
75
  */
52
- expect(msg: string): T | never;
76
+ expect(msg: string): T;
53
77
  }
54
78
 
55
79
  export interface IOptionTransform<T> {
56
80
  /**
57
- * Transforms the contained value of a Some with a provided function. Returns None if this Option is None.
58
- * @param fn The mapping function to apply to the contained value.
59
- * @returns An Option containing the result of applying fn to the original value if it was Some, else None.
60
- *
61
- * Usage Example:
62
- * const myOption = Some(5);
63
- * const newOption = myOption.map(x => x * 2); // Some(10)
81
+ * Maps an `Option<T>` to `Option<U>` by applying `fn` to the contained value.
64
82
  */
65
83
  map<U>(fn: (arg: T) => U): Option<U>;
66
84
 
67
85
  /**
68
- * Applies a function to the contained value if Some, otherwise returns a provided default.
69
- * @param defaultVal The default value to return if the Option is None.
70
- * @param fn The function to apply to the contained value if Some.
71
- * @returns The result of applying fn to the contained value if this Option is Some, else defaultVal.
72
- *
73
- * Usage Example:
74
- * const myOption = None();
75
- * const value = myOption.map_or(0, x => x * 2); // 0
86
+ * Returns the provided default (if `None`), or applies `fn` to the contained value.
76
87
  */
77
88
  map_or<U>(defaultVal: U, fn: (arg: T) => U): U;
89
+
90
+ /**
91
+ * Calls `fn` with the contained value for side effects, then returns the original option.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * Some(5)
96
+ * .inspect(x => console.log(`value: ${x}`))
97
+ * .map(x => x * 2)
98
+ * ```
99
+ */
100
+ inspect(f: (val: T) => void): this;
78
101
  }
79
102
 
80
103
  export interface IOptionCombine<T> {
81
104
  /**
82
- * Returns the passed Option if this Option is Some, else returns None.
83
- * @param opt The Option to return if this Option is Some.
84
- * @returns The passed Option if this Option is Some, else None.
85
- *
86
- * Usage Example:
87
- * const opt1 = Some(5);
88
- * const opt2 = Some(10);
89
- * const result = opt1.and(opt2); // Some(10)
105
+ * Returns `None` if `self` is `None`, otherwise returns `opt`.
90
106
  */
91
107
  and<U>(opt: Option<U>): Option<U>;
92
108
 
93
109
  /**
94
- * Returns the result of applying a function to the contained value if Some, otherwise returns None.
95
- * @param fn The function to apply to the contained value.
96
- * @returns An Option containing the result of applying fn to the original value if it was Some, else None.
97
- *
98
- * Usage Example:
99
- * const myOption = Some(5);
100
- * const newOption = myOption.and_then(x => Some(x * 2)); // Some(10)
110
+ * Returns `None` if `self` is `None`, otherwise calls `fn` with the wrapped value.
111
+ * This is the monadic bind operation (flatMap).
101
112
  */
102
113
  and_then<U>(fn: (arg: T) => Option<U>): Option<U>;
103
114
 
104
115
  /**
105
- * Returns the passed Option if this Option is None, else returns this Option.
106
- * @param opt The alternative Option to return if this Option is None.
107
- * @returns This Option if it is Some, otherwise the passed Option.
108
- *
109
- * Usage Example:
110
- * const opt1 = None();
111
- * const opt2 = Some(10);
112
- * const result = opt1.or(opt2); // Some(10)
116
+ * Returns `self` if `Some`, otherwise returns `opt`.
113
117
  */
114
- or<U>(opt: Option<U>): Option<T> | Option<U>;
118
+ or<U>(opt: Option<U>): Option<T | U>;
115
119
 
116
120
  /**
117
- * Returns the result of applying a function if this Option is None, else returns this Option.
118
- * @param fn The function that produces an Option to return if this Option is None.
119
- * @returns This Option if it is Some, otherwise the Option produced by fn.
120
- *
121
- * Usage Example:
122
- * const opt1 = None();
123
- * const result = opt1.or_else(() => Some(10)); // Some(10)
121
+ * Returns `self` if `Some`, otherwise calls `fn` and returns the result.
124
122
  */
125
- or_else<U>(fn: () => Option<U>): Option<T> | Option<U>;
123
+ or_else<U>(fn: () => Option<U>): Option<T | U>;
126
124
 
127
125
  /**
128
- * Returns None if both this and the passed Option are Some. Otherwise returns the Option that is Some.
129
- * @param optb The other Option to compare with.
130
- * @returns None if both Options are Some, otherwise the Option that is Some.
131
- *
132
- * Usage Example:
133
- * const opt1 = Some(5);
134
- * const opt2 = None();
135
- * const result = opt1.xor(opt2); // Some(5)
126
+ * Returns `Some` if exactly one of `self` and `optb` is `Some`, otherwise `None`.
136
127
  */
137
128
  xor(optb: Option<T>): Option<T>;
138
129
  }
139
130
 
140
131
  export interface IOptionUtility<T> {
141
132
  /**
142
- * Unwraps the Option, returning the contained value, or throws an error if the Option is None.
143
- * @returns The contained value if this Option is Some.
144
- * @throws Error if this Option is None.
133
+ * Returns the contained `Some` value, or throws.
145
134
  *
146
- * Usage Example:
147
- * const myOption = Some(5);
148
- * const value = myOption.unwrap(); // 5
135
+ * @throws Error if this is `None`
149
136
  */
150
- unwrap(): T | never;
137
+ unwrap(): T;
151
138
 
152
139
  /**
153
- * Returns the contained value if Some, else returns a provided alternative.
154
- * @param optb The alternative value to return if this Option is None.
155
- * @returns The contained value if this Option is Some, else optb.
156
- *
157
- * Usage Example:
158
- * const myOption = None();
159
- * const value = myOption.unwrap_or(10); // 10
140
+ * Returns the contained `Some` value, or the provided default.
160
141
  */
161
142
  unwrap_or(optb: T): T;
162
143
 
163
144
  /**
164
- * Returns the contained value if Some, else computes a value from a provided function.
165
- * @param fn The function to compute the alternative value from if this Option is None.
166
- * @returns The contained value if this Option is Some, else the result of fn.
167
- *
168
- * Usage Example:
169
- * const myOption = None();
170
- * const value = myOption.unwrap_or_else(() => 10); // 10
145
+ * Returns the contained `Some` value, or computes it from `fn`.
171
146
  */
172
147
  unwrap_or_else(fn: () => T): T;
173
148
 
174
149
  /**
175
- * Returns the contained value if Some, otherwise the default value for the type.
176
- * @returns The contained value if Some, else the type’s default value.
177
- *
178
- * Usage Example:
179
- * const myOption is None<number>();
180
- * const value = myOption.unwrap_or_default(); // 0
150
+ * Returns the contained `Some` value, or `null` if `None`.
181
151
  */
182
152
  unwrap_or_default(): T | null;
183
153
  }
184
154
 
185
155
  export interface IOptionMutate<T> {
186
156
  /**
187
- * Takes the contained value out of the Option, leaving a None in its place.
188
- * @returns The Option containing the original value before it was taken.
157
+ * Takes the value out of the option, leaving a `None` in its place.
189
158
  *
190
- * Usage Example:
191
- * const myOption = Some(5);
192
- * const takenValue = myOption.take(); // Some(5), myOption is now None
159
+ * @returns An `Option` containing the original value
193
160
  */
194
161
  take(): Option<T>;
195
162
 
196
163
  /**
197
- * Takes the contained value out of the Option if it satisfies a predicate, leaving a None in its place.
198
- * @param predicate The predicate to apply to the contained value.
199
- * @returns The Option containing the original value if the predicate returns true, otherwise None.
200
- *
201
- * Usage Example:
202
- * const myOption = Some(5);
203
- * const takenValue = myOption.take_if(x => x > 3); // Some(5), myOption is now None
164
+ * Takes the value out if it satisfies the predicate, leaving `None` in its place.
204
165
  */
205
166
  take_if(predicate: (arg: T) => boolean): Option<T>;
206
167
 
207
168
  /**
208
- * Replaces the contained value with another, returning the old value wrapped in an Option.
209
- * @param value The new value to put in the Option.
210
- * @returns An Option containing the old value.
211
- *
212
- * Usage Example:
213
- * const myOption = Some(5);
214
- * const oldValue = myOption.replace(10); // Some(5), myOption now contains 10
215
- *
216
- */
169
+ * Replaces the actual value with the provided one, returning the old value.
170
+ *
171
+ * @returns An `Option` containing the old value
172
+ */
217
173
  replace(value: T): Option<T>;
218
174
  }
219
175
 
220
176
  export interface IOptionZip<T> {
221
177
  /**
222
- * Combines two Option values into a single Option containing a tuple of their values if both are Some, otherwise returns None.
223
- * @param other The other Option to zip with.
224
- * @returns An Option containing a tuple of the two Option values if both are Some, otherwise None.
178
+ * Zips `self` with another `Option`.
225
179
  *
226
- * Usage Example:
227
- * const opt1 = Some(5);
228
- * const opt2 = Some("hello");
229
- * const zipped = opt1.zip(opt2); // Some([5, "hello"])
180
+ * Returns `Some([T, U])` if both are `Some`, otherwise `None`.
230
181
  */
231
182
  zip<U>(other: Option<U>): Option<[T, U]>;
232
183
 
233
184
  /**
234
- * Combines two Option values by applying a function if both are Some, otherwise returns None.
235
- * @param other The other Option to zip with.
236
- * @param f The function to apply to the values if both Options are Some.
237
- * @returns An Option containing the result of the function if both Options are Some, otherwise None.
185
+ * Zips `self` and another `Option` with a function.
238
186
  *
239
- * Usage Example:
240
- * const opt1 = Some(5);
241
- * const opt2 = Some(10);
242
- * const added = opt1.zip_with(opt2, (a, b) => a + b); // Some(15)
187
+ * Returns `Some(f(t, u))` if both are `Some`, otherwise `None`.
243
188
  */
244
189
  zip_with<U, R>(other: Option<U>, f: (val: T, other: U) => R): Option<R>;
245
190
  }
191
+
246
192
  export interface IOptionFilter<T> {
247
193
  /**
248
- * Applies a predicate to the contained value if Some, returns None if the predicate does not hold or if this Option is None.
249
- * @param predicate The predicate function to apply.
250
- * @returns The original Option if it is Some and the predicate holds, else None.
194
+ * Returns `None` if `self` is `None`, otherwise calls `predicate` with the wrapped value.
251
195
  *
252
- * Usage Example:
253
- * const myOption = Some(5);
254
- * const filteredOption = myOption.filter(x => x > 3); // Some(5)
196
+ * Returns `Some(t)` if the predicate returns `true`, otherwise `None`.
255
197
  */
256
198
  filter(predicate: (arg: T) => boolean): Option<T>;
257
199
  }
258
200
 
259
201
  export interface IOptionFlatten<T> {
260
202
  /**
261
- * Flattens a nested Option, if the Option contains another Option, returning the inner Option if it's Some.
262
- * @returns The contained Option if this is an Option of an Option and the inner Option is Some, otherwise None.
203
+ * Flattens an `Option<Option<U>>` to `Option<U>`.
204
+ *
205
+ * If `T` is not an `Option`, this returns the option unchanged.
206
+ */
207
+ flatten(): FlattenOption<T>;
208
+ }
209
+
210
+ // Forward declaration for Result types (will be imported at runtime)
211
+ type ResultLike<T, E> = { is_ok(): boolean; value: T | E; _tag: 'Ok' | 'Err' };
212
+
213
+ export interface IOptionConvert<T> {
214
+ /**
215
+ * Transforms `Option<T>` into `Result<T, E>`.
216
+ *
217
+ * Returns `Ok(v)` if `Some(v)`, otherwise `Err(err)`.
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * Some(5).ok_or("missing") // Ok(5)
222
+ * None().ok_or("missing") // Err("missing")
223
+ * ```
224
+ */
225
+ ok_or<E>(err: E): { _tag: 'Ok' | 'Err'; value: T | E };
226
+
227
+ /**
228
+ * Transforms `Option<T>` into `Result<T, E>` with a lazily computed error.
263
229
  *
264
- * Usage Example:
265
- * const opt = Some(Some(5));
266
- * const flattened = opt.flatten(); // Some(5)
230
+ * Returns `Ok(v)` if `Some(v)`, otherwise `Err(err())`.
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * Some(5).ok_or_else(() => new Error("missing")) // Ok(5)
235
+ * None().ok_or_else(() => new Error("missing")) // Err(Error)
236
+ * ```
237
+ */
238
+ ok_or_else<E>(err: () => E): { _tag: 'Ok' | 'Err'; value: T | E };
239
+ }
240
+
241
+ export interface IOptionAdvanced<T> {
242
+ /**
243
+ * Unzips an option containing a tuple into a tuple of options.
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * Some([1, "hi"]).unzip() // [Some(1), Some("hi")]
248
+ * None().unzip() // [None, None]
249
+ * ```
250
+ */
251
+ unzip(): T extends [infer A, infer B] ? [Option<A>, Option<B>] : never;
252
+
253
+ /**
254
+ * Transposes an `Option` of a `Result` into a `Result` of an `Option`.
255
+ *
256
+ * - `None` → `Ok(None)`
257
+ * - `Some(Ok(x))` → `Ok(Some(x))`
258
+ * - `Some(Err(e))` → `Err(e)`
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * Some(Ok(5)).transpose() // Ok(Some(5))
263
+ * Some(Err("e")).transpose() // Err("e")
264
+ * None().transpose() // Ok(None)
265
+ * ```
267
266
  */
268
- flatten<T extends Option<T>>(): Option<T>;
267
+ transpose(): T extends { _tag: 'Ok'; value: infer U }
268
+ ? { _tag: 'Ok'; value: Option<U> }
269
+ : T extends { _tag: 'Err'; value: infer E }
270
+ ? { _tag: 'Err'; value: E }
271
+ : { _tag: 'Ok'; value: Option<unknown> };
269
272
  }
270
273
 
274
+ /**
275
+ * The complete Option interface combining all capability interfaces.
276
+ */
271
277
  export interface IOption<T> extends
272
278
  IOptionCheck<T>,
273
279
  IOptionExpect<T>,
@@ -277,15 +283,31 @@ export interface IOption<T> extends
277
283
  IOptionMutate<T>,
278
284
  IOptionZip<T>,
279
285
  IOptionFilter<T>,
280
- IOptionFlatten<T> { }
281
-
282
- export class OptionSome<T> implements IOption<T> {
286
+ IOptionFlatten<T>,
287
+ IOptionConvert<T>,
288
+ IOptionAdvanced<T> {}
289
+
290
+ // ============================================================================
291
+ // OptionSome Implementation
292
+ // ============================================================================
293
+
294
+ /**
295
+ * The `Some` variant of `Option<T>`, representing a present value.
296
+ *
297
+ * Uses branded typing for nominal type safety.
298
+ *
299
+ * @typeParam T - The type of the contained value
300
+ */
301
+ export class OptionSome<out T> implements IOption<T> {
302
+ /** Brand for nominal typing - ensures OptionSome is distinct from OptionNone */
303
+ declare readonly [SomeBrand]: T;
304
+
305
+ /** Discriminant tag for runtime type checking */
283
306
  readonly _tag = 'Some' as const;
284
- // @ts-ignore
285
- readonly _T: T;
286
307
 
287
- constructor(readonly value: T) { }
308
+ constructor(public value: T) {}
288
309
 
310
+ // Type guards
289
311
  is_some(): this is OptionSome<T> {
290
312
  return true;
291
313
  }
@@ -294,22 +316,50 @@ export class OptionSome<T> implements IOption<T> {
294
316
  return f(this.value);
295
317
  }
296
318
 
297
- is_none(): this is never {
319
+ is_none(): this is OptionNone<T> {
298
320
  return false;
299
321
  }
300
322
 
323
+ is_none_or(f: (arg: T) => boolean): boolean {
324
+ return f(this.value);
325
+ }
326
+
327
+ // Extraction
301
328
  expect(_msg: string): T {
302
329
  return this.value;
303
330
  }
304
331
 
305
- map<U>(fn: (arg: T) => U): Option<U> {
306
- return new OptionSome<U>(fn(this.value));
332
+ unwrap(): T {
333
+ return this.value;
334
+ }
335
+
336
+ unwrap_or(_optb: T): T {
337
+ return this.value;
338
+ }
339
+
340
+ unwrap_or_else(_fn: () => T): T {
341
+ return this.value;
342
+ }
343
+
344
+ unwrap_or_default(): T {
345
+ return this.value;
346
+ }
347
+
348
+ // Transformations
349
+ map<U>(fn: (arg: T) => U): OptionSome<U> {
350
+ return new OptionSome(fn(this.value));
307
351
  }
308
352
 
309
353
  map_or<U>(_defaultVal: U, fn: (arg: T) => U): U {
310
354
  return fn(this.value);
311
355
  }
312
356
 
357
+ inspect(f: (val: T) => void): this {
358
+ f(this.value);
359
+ return this;
360
+ }
361
+
362
+ // Combinators
313
363
  and<U>(opt: Option<U>): Option<U> {
314
364
  return opt;
315
365
  }
@@ -318,106 +368,134 @@ export class OptionSome<T> implements IOption<T> {
318
368
  return fn(this.value);
319
369
  }
320
370
 
321
- filter(predicate: (arg: T) => boolean): Option<T> {
322
- if (predicate(this.value)) {
323
- return this;
324
- }
325
-
326
- return None<T>();
327
- }
328
-
329
- or<U>(_opt: Option<U>): Option<T> {
330
- return this as any;
371
+ /**
372
+ * On Some, `or` returns self.
373
+ * Returns this instance typed as Option<T | U> for type compatibility.
374
+ */
375
+ or<U>(_opt: Option<U>): OptionSome<T> {
376
+ return this;
331
377
  }
332
378
 
333
- or_else<U>(_fn: () => Option<U>): Option<T> {
334
- return this as any;
379
+ /**
380
+ * On Some, `or_else` returns self.
381
+ */
382
+ or_else<U>(_fn: () => Option<U>): OptionSome<T> {
383
+ return this;
335
384
  }
336
385
 
337
386
  xor(optb: Option<T>): Option<T> {
338
387
  if (optb.is_some()) {
339
- return None<T>();
388
+ return new OptionNone();
340
389
  }
341
-
342
390
  return this;
343
391
  }
344
392
 
345
- unwrap(): T {
346
- return this.value;
347
- }
348
-
349
- unwrap_or(optb: T): T {
350
- return this.value;
351
- }
352
-
353
- unwrap_or_else(_fn: () => T): T {
354
- return this.value;
355
- }
356
-
357
- unwrap_or_default(): T | null {
358
- return this.value;
393
+ // Filtering
394
+ filter(predicate: (arg: T) => boolean): Option<T> {
395
+ if (predicate(this.value)) {
396
+ return this;
397
+ }
398
+ return new OptionNone();
359
399
  }
360
400
 
401
+ // Mutation
361
402
  take(): Option<T> {
362
403
  const value = this.value;
363
- // @ts-ignore "administrative override" :-)
364
- this.value = undefined as any;
365
- return new OptionSome<T>(value);
404
+ // Mutate in place - this is intentional per the Rust API
405
+ (this as { value: T | undefined }).value = undefined as any;
406
+ return new OptionSome(value);
366
407
  }
367
408
 
368
409
  take_if(predicate: (arg: T) => boolean): Option<T> {
369
410
  if (predicate(this.value)) {
370
411
  return this.take();
371
412
  }
372
-
373
- return None<T>();
413
+ return new OptionNone();
374
414
  }
375
415
 
376
416
  replace(value: T): Option<T> {
377
417
  const oldValue = this.value;
378
- // @ts-ignore "administrative override" :-)
379
418
  this.value = value;
380
- return new OptionSome<T>(oldValue);
419
+ return new OptionSome(oldValue);
381
420
  }
382
421
 
422
+ // Zipping
383
423
  zip<U>(other: Option<U>): Option<[T, U]> {
384
424
  if (other.is_some()) {
385
- return new OptionSome<[T, U]>([this.value, other.unwrap()]);
425
+ return new OptionSome<[T, U]>([this.value, other.value]);
386
426
  }
387
-
388
- return new OptionNone<[T, U]>();
427
+ return new OptionNone();
389
428
  }
390
429
 
391
430
  zip_with<U, R>(other: Option<U>, f: (val: T, other: U) => R): Option<R> {
392
431
  if (other.is_some()) {
393
- return new OptionSome<R>(f(this.value, other.unwrap()));
432
+ return new OptionSome(f(this.value, other.value));
394
433
  }
434
+ return new OptionNone();
435
+ }
436
+
437
+ // Flattening
438
+ flatten(): FlattenOption<T> {
439
+ const val = this.value;
440
+ if (val instanceof OptionSome) {
441
+ return val as FlattenOption<T>;
442
+ }
443
+ if (val instanceof OptionNone) {
444
+ return val as FlattenOption<T>;
445
+ }
446
+ // T is not an Option, return self unchanged
447
+ return this as unknown as FlattenOption<T>;
448
+ }
449
+
450
+ // Conversion to Result
451
+ ok_or<E>(_err: E): { _tag: 'Ok'; value: T } {
452
+ return { _tag: 'Ok', value: this.value };
453
+ }
395
454
 
396
- return new OptionNone<R>();
455
+ ok_or_else<E>(_err: () => E): { _tag: 'Ok'; value: T } {
456
+ return { _tag: 'Ok', value: this.value };
397
457
  }
398
458
 
399
- flatten<T extends Option<T>>(): Option<T> {
400
- if (this.value instanceof OptionSome) {
401
- // If the value is an OptionSome, we return it directly.
402
- return this.value;
459
+ // Advanced
460
+ unzip(): T extends [infer A, infer B] ? [Option<A>, Option<B>] : never {
461
+ const [a, b] = this.value as [unknown, unknown];
462
+ return [new OptionSome(a), new OptionSome(b)] as any;
463
+ }
464
+
465
+ transpose(): any {
466
+ const result = this.value as { _tag: 'Ok' | 'Err'; value: unknown; is_ok?(): boolean };
467
+ if (result._tag === 'Ok' || (result.is_ok && result.is_ok())) {
468
+ return { _tag: 'Ok', value: new OptionSome(result.value) };
403
469
  } else {
404
- // If the value is not an OptionSome (meaning it's an OptionNone or another type),
405
- // we return None<T>(). This assumes that None<T>() creates an OptionNone<T> instance.
406
- return None<T>();
470
+ return { _tag: 'Err', value: result.value };
407
471
  }
408
472
  }
409
473
  }
410
474
 
411
- export class OptionNone<T> implements IOption<T> {
412
- private readonly _tag: 'None' = 'None';
413
- // @ts-ignore
414
- private readonly _T: T;
415
-
416
- is_some(): this is never {
475
+ // ============================================================================
476
+ // OptionNone Implementation
477
+ // ============================================================================
478
+
479
+ /**
480
+ * The `None` variant of `Option<T>`, representing absence of a value.
481
+ *
482
+ * Uses branded typing for nominal type safety.
483
+ *
484
+ * @typeParam T - The phantom type parameter for type compatibility
485
+ */
486
+ export class OptionNone<out T = never> implements IOption<T> {
487
+ /** Brand for nominal typing - ensures OptionNone is distinct from OptionSome */
488
+ declare readonly [NoneBrand]: void;
489
+
490
+ /** Discriminant tag for runtime type checking */
491
+ readonly _tag = 'None' as const;
492
+
493
+ // Type guards
494
+ is_some(): this is OptionSome<T> {
417
495
  return false;
418
496
  }
419
497
 
420
- is_some_and(_f: (arg: T) => boolean): boolean {
498
+ is_some_and(_f: (arg: T) => boolean): false {
421
499
  return false;
422
500
  }
423
501
 
@@ -425,28 +503,60 @@ export class OptionNone<T> implements IOption<T> {
425
503
  return true;
426
504
  }
427
505
 
506
+ is_none_or(_f: (arg: T) => boolean): true {
507
+ return true;
508
+ }
509
+
510
+ // Extraction
428
511
  expect(msg: string): never {
429
512
  throw new Error(msg);
430
513
  }
431
514
 
432
- map<U>(_fn: (arg: any) => U): Option<U> {
433
- return this as any;
515
+ unwrap(): never {
516
+ throw new Error('Called Option.unwrap() on a None value');
517
+ }
518
+
519
+ unwrap_or(optb: T): T {
520
+ return optb;
521
+ }
522
+
523
+ unwrap_or_else(fn: () => T): T {
524
+ return fn();
525
+ }
526
+
527
+ unwrap_or_default(): null {
528
+ return null;
529
+ }
530
+
531
+ // Transformations
532
+ /**
533
+ * On None, map returns None with updated type parameter.
534
+ */
535
+ map<U>(_fn: (arg: T) => U): OptionNone<U> {
536
+ return new OptionNone<U>();
434
537
  }
435
538
 
436
539
  map_or<U>(defaultVal: U, _fn: (arg: T) => U): U {
437
540
  return defaultVal;
438
541
  }
439
542
 
440
- and<U>(_opt: Option<U>): Option<U> {
441
- return this as any;
543
+ inspect(_f: (val: T) => void): this {
544
+ return this;
442
545
  }
443
546
 
444
- and_then<U>(_fn: (arg: any) => Option<U>): Option<U> {
445
- return this as any;
547
+ // Combinators
548
+ /**
549
+ * On None, `and` returns None with updated type parameter.
550
+ */
551
+ and<U>(_opt: Option<U>): OptionNone<U> {
552
+ return new OptionNone<U>();
446
553
  }
447
554
 
448
- filter(_predicate: (arg: T) => boolean): Option<T> {
449
- return this as any;
555
+ /**
556
+ * On None, `and_then` returns None with updated type parameter.
557
+ */
558
+ and_then<U>(_fn: (arg: T) => Option<U>): OptionNone<U> {
559
+ return new OptionNone<U>();
450
560
  }
451
561
 
452
562
  or<U>(opt: Option<U>): Option<U> {
@@ -461,64 +571,168 @@ export class OptionNone<T> implements IOption<T> {
461
571
  return optb;
462
572
  }
463
573
 
464
- unwrap(): never {
465
- throw new Error('Called Option.unwrap() on a None value');
574
+ // Filtering
575
+ /**
576
+ * On None, filter returns None.
577
+ */
578
+ filter(_predicate: (arg: T) => boolean): OptionNone<T> {
579
+ return this;
466
580
  }
467
581
 
468
- unwrap_or(optb: any): any {
469
- return optb;
582
+ // Mutation
583
+ take(): OptionNone<T> {
584
+ return this;
470
585
  }
471
586
 
472
- unwrap_or_else(fn: () => any): any {
473
- return fn();
587
+ take_if(_predicate: (arg: T) => boolean): OptionNone<T> {
588
+ return this;
474
589
  }
475
590
 
476
- unwrap_or_default(): T | null {
477
- return null as any;
591
+ /**
592
+ * On None, replace returns Some with the provided value.
593
+ *
594
+ * Note: This differs from Rust's semantics where replace would mutate
595
+ * self to become Some and return the old value (None). Here we maintain
596
+ * immutability - self remains None and we return Some(value).
597
+ */
598
+ replace(value: T): OptionSome<T> {
599
+ return new OptionSome<T>(value);
478
600
  }
479
601
 
480
- take(): Option<T> {
481
- return this;
602
+ // Zipping
603
+ zip<U>(_other: Option<U>): OptionNone<[T, U]> {
604
+ return new OptionNone();
482
605
  }
483
606
 
484
- take_if(_predicate: (arg: T) => boolean): Option<T> {
485
- return this;
607
+ zip_with<U, R>(_other: Option<U>, _f: (val: T, other: U) => R): OptionNone<R> {
608
+ return new OptionNone();
486
609
  }
487
610
 
488
- replace(value: T): Option<T> {
489
- return new OptionSome<T>(value);
611
+ // Flattening
612
+ flatten(): FlattenOption<T> {
613
+ return new OptionNone() as FlattenOption<T>;
490
614
  }
491
615
 
492
- zip<U>(other: Option<U>): Option<[T, U]> {
493
- return None<[T, U]>();
616
+ // Conversion to Result
617
+ ok_or<E>(err: E): { _tag: 'Err'; value: E } {
618
+ return { _tag: 'Err', value: err };
619
+ }
620
+
621
+ ok_or_else<E>(err: () => E): { _tag: 'Err'; value: E } {
622
+ return { _tag: 'Err', value: err() };
494
623
  }
495
624
 
496
- zip_with<U, R>(_other: Option<U>, _f: (val: T, other: U) => R): Option<R> {
497
- return None<R>();
625
+ // Advanced
626
+ unzip(): T extends [infer A, infer B] ? [Option<A>, Option<B>] : never {
627
+ return [new OptionNone(), new OptionNone()] as any;
498
628
  }
499
629
 
500
- flatten<T extends Option<T>>(): Option<T> {
501
- return this as any;
630
+ transpose(): any {
631
+ return { _tag: 'Ok', value: new OptionNone() };
502
632
  }
503
633
  }
504
634
 
505
- export const Some = <T>(val: T): Option<T> => {
506
- return new OptionSome<T>(val);
635
+ // ============================================================================
636
+ // Factory Functions
637
+ // ============================================================================
638
+
639
+ /**
640
+ * Creates a `Some` option containing the given value.
641
+ *
642
+ * @example
643
+ * const opt = Some(42); // Option<number>
644
+ * const mapped = opt.map(x => x * 2); // Option<number>
645
+ */
646
+ export const Some = <T>(val: T): OptionSome<T> => {
647
+ return new OptionSome(val);
507
648
  };
508
649
 
509
- export const None = <T>(): Option<T> => {
650
+ /**
651
+ * Creates a `None` option of the specified type.
652
+ *
653
+ * @example
654
+ * const opt = None<number>(); // Option<number>
655
+ * const fallback = opt.or(Some(0)); // Option<number>
656
+ */
657
+ export const None = <T = never>(): OptionNone<T> => {
510
658
  return new OptionNone<T>();
511
659
  };
512
660
 
513
- export const option_from_nullable =
514
- <T>(val: T | null | undefined): Option<T> => {
515
- if (val === null || val === undefined) {
516
- return None<T>();
517
- }
661
+ // ============================================================================
662
+ // Utility Functions
663
+ // ============================================================================
664
+
665
+ /**
666
+ * Converts a nullable value to an Option.
667
+ *
668
+ * Returns `Some(val)` if the value is not null/undefined, otherwise `None`.
669
+ *
670
+ * @example
671
+ * const opt1 = option_from_nullable("hello"); // Some("hello")
672
+ * const opt2 = option_from_nullable(null); // None
673
+ * const opt3 = option_from_nullable(undefined); // None
674
+ */
675
+ export const option_from_nullable = <T>(val: T | null | undefined): Option<NonNullable<T>> => {
676
+ if (val === null || val === undefined) {
677
+ return None();
678
+ }
679
+ return Some(val as NonNullable<T>);
680
+ };
518
681
 
519
- return Some(val);
520
- };
682
+ /**
683
+ * Converts a Promise to an Option wrapped in a Promise.
684
+ *
685
+ * If the promise resolves, returns `Some(value)`.
686
+ * If it rejects, returns `None`.
687
+ *
688
+ * @example
689
+ * const opt = await option_from_promise(fetch('/api/data'));
690
+ * // Option<Response>
691
+ */
692
+ export const option_from_promise = <T>(promise: Promise<T>): Promise<Option<T>> =>
693
+ promise.then(Some).catch(() => None<T>());
694
+
695
+ // ============================================================================
696
+ // Advanced Type Utilities
697
+ // ============================================================================
698
+
699
+ /**
700
+ * Type-safe match expression for Option.
701
+ *
702
+ * @example
703
+ * const message = matchOption(option, {
704
+ * Some: (value) => `Found: ${value}`,
705
+ * None: () => "Not found",
706
+ * });
707
+ */
708
+ export function matchOption<T, R>(
709
+ option: Option<T>,
710
+ handlers: {
711
+ Some: (value: T) => R;
712
+ None: () => R;
713
+ }
714
+ ): R {
715
+ if (option.is_some()) {
716
+ return handlers.Some(option.value);
717
+ } else {
718
+ return handlers.None();
719
+ }
720
+ }
521
721
 
522
- export const option_from_promise =
523
- <T>(promise: Promise<T>): Promise<Option<T>> =>
524
- promise.then(Some).catch(() => None<T>());
722
+ /**
723
+ * Transposes an Option of a Result into a Result of an Option.
724
+ *
725
+ * - `None` -> `Ok(None)`
726
+ * - `Some(Ok(x))` -> `Ok(Some(x))`
727
+ * - `Some(Err(e))` -> `Err(e)`
728
+ *
729
+ * This is useful for error handling in option chains.
730
+ */
731
+ // Note: This requires importing Result types, so we use a type-only approach
732
+ export type TransposeOption<T> = T extends { is_ok(): boolean; value: infer V }
733
+ ? T extends { _tag: 'Ok' }
734
+ ? { _tag: 'Ok'; value: Option<V> }
735
+ : T extends { _tag: 'Err' }
736
+ ? T
737
+ : never
738
+ : never;