UNPKG

45.6 kBTypeScriptView Raw
1/**
2 [[include:doc/maybe.md]]
3
4 @module
5 */
6/**
7 Discriminant for the {@linkcode Just} and {@linkcode Nothing} type instances.
8
9 You can use the discriminant via the `variant` property of {@linkcode Maybe}
10 instances if you need to match explicitly on it.
11 */
12export declare const Variant: {
13 readonly Just: "Just";
14 readonly Nothing: "Nothing";
15};
16export type Variant = keyof typeof Variant;
17export interface JustJSON<T> {
18 variant: 'Just';
19 value: T;
20}
21export interface NothingJSON {
22 variant: 'Nothing';
23}
24export type MaybeJSON<T> = JustJSON<T> | NothingJSON;
25declare class MaybeImpl<T> {
26 private repr;
27 constructor(value?: T | null | undefined);
28 /**
29 Create a `Maybe` from any value.
30
31 To specify that the result should be interpreted as a specific type, you may
32 invoke `Maybe.of` with an explicit type parameter:
33
34 ```ts
35 const foo = Maybe.of<string>(null);
36 ```
37
38 This is usually only important in two cases:
39
40 1. If you are intentionally constructing a `Nothing` from a known `null` or
41 undefined value *which is untyped*.
42 2. If you are specifying that the type is more general than the value passed
43 (since TypeScript can define types as literals).
44
45 @template T The type of the item contained in the `Maybe`.
46 @param value The value to wrap in a `Maybe`. If it is `undefined` or `null`,
47 the result will be `Nothing`; otherwise it will be the type of
48 the value passed.
49 */
50 static of<F extends (...args: any) => {}>(value: F): Maybe<F>;
51 static of<T extends {}, F extends (...args: any) => T | null | undefined>(value: F): never;
52 static of<F extends (...args: any) => null | undefined>(value: F): never;
53 static of<T>(value: T | null | undefined): Maybe<T>;
54 /**
55 Create an instance of `Maybe.Just`.
56
57 @template T The type of the item contained in the `Maybe`.
58 @param value The value to wrap in a `Maybe.Just`.
59 @returns An instance of `Maybe.Just<T>`.
60 @throws If you pass `null` or `undefined`.
61 */
62 static just<F extends (...args: any) => {}>(value: F): Maybe<F>;
63 static just<T extends {}, F extends (...args: any) => T | null | undefined>(value: F): never;
64 static just<F extends (...args: any) => null | undefined>(value: F): never;
65 static just<T extends {}>(value: T): Maybe<T>;
66 /**
67 Create an instance of `Maybe.Nothing`.
68
69 If you want to create an instance with a specific type, e.g. for use in a
70 function which expects a `Maybe<T>` where the `<T>` is known but you have no
71 value to give it, you can use a type parameter:
72
73 ```ts
74 const notString = Maybe.nothing<string>();
75 ```
76
77 @template T The type of the item contained in the `Maybe`.
78 @returns An instance of `Maybe.Nothing<T>`.
79 */
80 static nothing<T>(_?: null): Nothing<T>;
81 /** Distinguish between the `Just` and `Nothing` {@link Variant variants}. */
82 get variant(): Variant;
83 /**
84 The wrapped value.
85
86 @warning throws if you access this from a {@linkcode Just}
87 */
88 get value(): T;
89 /** Is the {@linkcode Maybe} a {@linkcode Just}? */
90 get isJust(): boolean;
91 /** Is the {@linkcode Maybe} a {@linkcode Nothing}? */
92 get isNothing(): boolean;
93 /** Method variant for {@linkcode map} */
94 map<U extends {}>(mapFn: (t: T) => U): Maybe<U>;
95 /** Method variant for {@link mapOr|`mapOr`} */
96 mapOr<U>(orU: U, mapFn: (t: T) => U): U;
97 /** Method variant for {@linkcode mapOrElse} */
98 mapOrElse<U>(orElseFn: () => U, mapFn: (t: T) => U): U;
99 /** Method variant for {@linkcode match} */
100 match<U>(matcher: Matcher<T, U>): U;
101 /** Method variant for {@linkcode or} */
102 or(mOr: Maybe<T>): Maybe<T>;
103 /** Method variant for {@linkcode orElse} */
104 orElse(orElseFn: () => Maybe<T>): Maybe<T>;
105 /** Method variant for {@linkcode and} */
106 and<U>(mAnd: Maybe<U>): Maybe<U>;
107 /** Method variant for {@linkcode andThen} */
108 andThen<U>(andThenFn: (t: T) => Maybe<U>): Maybe<U>;
109 /** Method variant for {@linkcode unwrapOr} */
110 unwrapOr<U>(defaultValue: U): T | U;
111 /** Method variant for {@linkcode unwrapOrElse} */
112 unwrapOrElse<U>(elseFn: () => U): T | U;
113 /** Method variant for {@linkcode toString} */
114 toString(): string;
115 /** Method variant for {@linkcode toJSON} */
116 toJSON(): MaybeJSON<unknown>;
117 /** Method variant for {@linkcode equals} */
118 equals(comparison: Maybe<T>): boolean;
119 /** Method variant for {@linkcode ap} */
120 ap<A, B extends {}>(this: Maybe<(val: A) => B>, val: Maybe<A>): Maybe<B>;
121 /**
122 Method variant for {@linkcode get}
123
124 If you have a `Maybe` of an object type, you can do `thatMaybe.get('a key')`
125 to look up the next layer down in the object.
126
127 ```ts
128 type DeepOptionalType = {
129 something?: {
130 with?: {
131 deeperKeys?: string;
132 }
133 }
134 };
135
136 const fullySet: DeepType = {
137 something: {
138 with: {
139 deeperKeys: 'like this'
140 }
141 }
142 };
143
144 const deepJust = Maybe.of(fullySet)
145 .get('something')
146 .get('with')
147 .get('deeperKeys');
148
149 console.log(deepJust); // Just('like this');
150
151 const partiallyUnset: DeepType = { something: { } };
152
153 const deepEmpty = Maybe.of(partiallyUnset)
154 .get('something')
155 .get('with')
156 .get('deeperKeys');
157
158 console.log(deepEmpty); // Nothing
159 ```
160 */
161 get<K extends keyof T>(key: K): Maybe<NonNullable<T[K]>>;
162}
163/**
164 A `Just` instance is the *present* variant instance of the
165 {@linkcode Maybe} type, representing the presence of a
166 value which may be absent. For a full discussion, see the module docs.
167
168 @template T The type wrapped in this `Just` variant of `Maybe`.
169 */
170export interface Just<T> extends MaybeImpl<T> {
171 /** `Just` is always {@linkcode Variant.Just}. */
172 readonly variant: 'Just';
173 /** The wrapped value. */
174 value: T;
175 isJust: true;
176 isNothing: false;
177}
178/**
179 A `Nothing` instance is the *absent* variant instance of the {@linkcode Maybe}
180 type, representing the presence of a value which may be absent. For a full
181 discussion, see the module docs.
182
183 @template T The type which would be wrapped in a {@linkcode Just} variant of
184 the {@linkcode Maybe}.
185 */
186export interface Nothing<T> extends Omit<MaybeImpl<T>, 'value'> {
187 /** `Nothing` is always {@linkcode Variant.Nothing}. */
188 readonly variant: 'Nothing';
189 isJust: false;
190 isNothing: true;
191}
192/**
193 Create a {@linkcode Maybe} instance which is a {@linkcode Just}.
194
195 `null` and `undefined` are allowed by the type signature so that the
196 function may `throw` on those rather than constructing a type like
197 `Maybe<undefined>`.
198
199 @template T The type of the item contained in the `Maybe`.
200 @param value The value to wrap in a `Maybe.Just`.
201 @returns An instance of `Maybe.Just<T>`.
202 @throws If you pass `null` or `undefined`.
203 */
204export declare const just: typeof MaybeImpl.just;
205/**
206 Is the {@linkcode Maybe} a {@linkcode Just}?
207
208 @template T The type of the item contained in the `Maybe`.
209 @param maybe The `Maybe` to check.
210 @returns A type guarded `Just`.
211 */
212export declare function isJust<T>(maybe: Maybe<T>): maybe is Just<T>;
213/**
214 Is the {@linkcode Maybe} a {@linkcode Nothing}?
215
216 @template T The type of the item contained in the `Maybe`.
217 @param maybe The `Maybe` to check.
218 @returns A type guarded `Nothing`.
219*/
220export declare function isNothing<T>(maybe: Maybe<T>): maybe is Nothing<T>;
221/**
222 Create a {@linkcode Maybe} instance which is a {@linkcode Nothing}.
223
224 If you want to create an instance with a specific type, e.g. for use in a
225 function which expects a `Maybe<T>` where the `<T>` is known but you have no
226 value to give it, you can use a type parameter:
227
228 ```ts
229 const notString = Maybe.nothing<string>();
230 ```
231
232 @template T The type of the item contained in the `Maybe`.
233 @returns An instance of `Maybe.Nothing<T>`.
234 */
235export declare const nothing: typeof MaybeImpl.nothing;
236/**
237 Create a {@linkcode Maybe} from any value.
238
239 To specify that the result should be interpreted as a specific type, you may
240 invoke `Maybe.of` with an explicit type parameter:
241
242 ```ts
243 import * as Maybe from 'true-myth/maybe';
244 const foo = Maybe.of<string>(null);
245 ```
246
247 This is usually only important in two cases:
248
249 1. If you are intentionally constructing a `Nothing` from a known `null` or
250 undefined value *which is untyped*.
251 2. If you are specifying that the type is more general than the value passed
252 (since TypeScript can define types as literals).
253
254 @template T The type of the item contained in the `Maybe`.
255 @param value The value to wrap in a `Maybe`. If it is `undefined` or `null`,
256 the result will be `Nothing`; otherwise it will be the type of
257 the value passed.
258 */
259export declare const of: typeof MaybeImpl.of;
260/**
261 Map over a {@linkcode Maybe} instance: apply the function to the wrapped value
262 if the instance is {@linkcode Just}, and return {@linkcode Nothing} if the
263 instance is `Nothing`.
264
265 `map` works a lot like `Array.prototype.map`: `Maybe` and `Array` are both
266 *containers* for other things. If you have no items in an array of numbers
267 named `foo` and call `foo.map(x => x + 1)`, you'll still just have an array
268 with nothing in it. But if you have any items in the array (`[2, 3]`), and you
269 call `foo.map(x => x + 1)` on it, you'll get a new array with each of those
270 items inside the array "container" transformed (`[3, 4]`).
271
272 That's exactly what's happening with `map`. If the container is *empty* – the
273 `Nothing` variantyou just get back an empty container. If the container has
274 something in it – the `Just` variant – you get back a container with the item
275 inside transformed.
276
277 (So... why not just use an array? The biggest reason is that an array can be
278 any length. With a `Maybe`, we're capturing the idea of "something or nothing"
279 rather than "0 to n" items. And this lets us implement a whole set of *other*
280 interfaces, like those in this module.)
281
282 #### Examples
283
284 ```ts
285 const length = (s: string) => s.length;
286
287 const justAString = Maybe.just('string');
288 const justTheStringLength = map(length, justAString);
289 console.log(justTheStringLength.toString()); // Just(6)
290
291 const notAString = Maybe.nothing<string>();
292 const notAStringLength = map(length, notAString);
293 console.log(notAStringLength.toString()); // "Nothing"
294 ```
295
296 @template T The type of the wrapped value.
297 @template U The type of the wrapped value of the returned `Maybe`.
298 @param mapFn The function to apply the value to if `Maybe` is `Just`.
299 @returns A function accepting a `Maybe<T>`, which will produce `Maybe<U>`
300 after applying `mapFn`.
301 */
302export declare function map<T, U extends {}>(mapFn: (t: T) => U): (maybe: Maybe<T>) => Maybe<U>;
303/**
304 Map over a {@linkcode Maybe} instance: apply the function to the wrapped value
305 if the instance is {@linkcode Just}, and return {@linkcode Nothing} if the
306 instance is `Nothing`.
307
308 `map` works a lot like `Array.prototype.map`: `Maybe` and `Array` are both
309 *containers* for other things. If you have no items in an array of numbers
310 named `foo` and call `foo.map(x => x + 1)`, you'll still just have an array
311 with nothing in it. But if you have any items in the array (`[2, 3]`), and you
312 call `foo.map(x => x + 1)` on it, you'll get a new array with each of those
313 items inside the array "container" transformed (`[3, 4]`).
314
315 That's exactly what's happening with `map`. If the container is *empty* – the
316 `Nothing` variant – you just get back an empty container. If the container has
317 something in it – the `Just` variant – you get back a container with the item
318 inside transformed.
319
320 (So... why not just use an array? The biggest reason is that an array can be
321 any length. With a `Maybe`, we're capturing the idea of "something or nothing"
322 rather than "0 to n" items. And this lets us implement a whole set of *other*
323 interfaces, like those in this module.)
324
325 #### Examples
326
327 ```ts
328 const length = (s: string) => s.length;
329
330 const justAString = Maybe.just('string');
331 const justTheStringLength = map(length, justAString);
332 console.log(justTheStringLength.toString()); // Just(6)
333
334 const notAString = Maybe.nothing<string>();
335 const notAStringLength = map(length, notAString);
336 console.log(notAStringLength.toString()); // "Nothing"
337 ```
338
339 @template T The type of the wrapped value.
340 @template U The type of the wrapped value of the returned `Maybe`.
341 @param mapFn The function to apply the value to if `Maybe` is `Just`.
342 @param maybe The `Maybe` instance to map over.
343 @returns A new `Maybe` with the result of applying `mapFn` to the value in
344 a `Just`, or `Nothing` if `maybe` is `Nothing`.
345 */
346export declare function map<T, U extends {}>(mapFn: (t: T) => U, maybe: Maybe<T>): Maybe<U>;
347/**
348 Map over a {@linkcode Maybe} instance and get out the value if `maybe` is a
349 {@linkcode Just}, or return a default value if `maybe` is a
350 {@linkcode Nothing}.
351
352 #### Examples
353
354 ```ts
355 const length = (s: string) => s.length;
356
357 const justAString = Maybe.just('string');
358 const theStringLength = mapOr(0, length, justAString);
359 console.log(theStringLength); // 6
360
361 const notAString = Maybe.nothing<string>();
362 const notAStringLength = mapOr(0, length, notAString)
363 console.log(notAStringLength); // 0
364 ```
365
366 @template T The type of the wrapped value.
367 @template U The type of the wrapped value of the returned `Maybe`.
368 @param orU The default value to use if `maybe` is `Nothing`
369 @param mapFn The function to apply the value to if `Maybe` is `Just`
370 @param maybe The `Maybe` instance to map over.
371 */
372export declare function mapOr<T, U>(orU: U, mapFn: (t: T) => U, maybe: Maybe<T>): U;
373export declare function mapOr<T, U>(orU: U, mapFn: (t: T) => U): (maybe: Maybe<T>) => U;
374export declare function mapOr<T, U>(orU: U): (mapFn: (t: T) => U) => (maybe: Maybe<T>) => U;
375/**
376 Map over a {@linkcode Maybe} instance and get out the value if `maybe` is a
377 {@linkcode Just}, or use a function to construct a default value if `maybe` is
378 {@linkcode Nothing}.
379
380 #### Examples
381
382 ```ts
383 const length = (s: string) => s.length;
384 const getDefault = () => 0;
385
386 const justAString = Maybe.just('string');
387 const theStringLength = mapOrElse(getDefault, length, justAString);
388 console.log(theStringLength); // 6
389
390 const notAString = Maybe.nothing<string>();
391 const notAStringLength = mapOrElse(getDefault, length, notAString)
392 console.log(notAStringLength); // 0
393 ```
394
395 @template T The type of the wrapped value.
396 @template U The type of the wrapped value of the returned `Maybe`.
397 @param orElseFn The function to apply if `maybe` is `Nothing`.
398 @param mapFn The function to apply to the wrapped value if `maybe` is
399 `Just`
400 @param maybe The `Maybe` instance to map over.
401 */
402export declare function mapOrElse<T, U>(orElseFn: () => U, mapFn: (t: T) => U, maybe: Maybe<T>): U;
403export declare function mapOrElse<T, U>(orElseFn: () => U, mapFn: (t: T) => U): (maybe: Maybe<T>) => U;
404export declare function mapOrElse<T, U>(orElseFn: () => U): (mapFn: (t: T) => U) => (maybe: Maybe<T>) => U;
405/**
406 You can think of this like a short-circuiting logical "and" operation on a
407 {@linkcode Maybe} type. If `maybe` is {@linkcode just}, then the result is the
408 `andMaybe`. If `maybe` is {@linkcode Nothing}, the result is `Nothing`.
409
410 This is useful when you have another `Maybe` value you want to provide if and
411 *only if* you have a `Just` – that is, when you need to make sure that if you
412 `Nothing`, whatever else you're handing a `Maybe` to *also* gets a `Nothing`.
413
414 Notice that, unlike in [`map`](#map) or its variants, the original `maybe` is
415 not involved in constructing the new `Maybe`.
416
417 #### Examples
418
419 ```ts
420 import Maybe from 'true-myth/maybe';
421
422 const justA = Maybe.just('A');
423 const justB = Maybe.just('B');
424 const nothing: Maybe<number> = nothing();
425
426 console.log(Maybe.and(justB, justA).toString()); // Just(B)
427 console.log(Maybe.and(justB, nothing).toString()); // Nothing
428 console.log(Maybe.and(nothing, justA).toString()); // Nothing
429 console.log(Maybe.and(nothing, nothing).toString()); // Nothing
430 ```
431
432 @template T The type of the initial wrapped value.
433 @template U The type of the wrapped value of the returned `Maybe`.
434 @param andMaybe The `Maybe` instance to return if `maybe` is `Just`
435 @param maybe The `Maybe` instance to check.
436 @return `Nothing` if the original `maybe` is `Nothing`, or `andMaybe`
437 if the original `maybe` is `Just`.
438 */
439export declare function and<T, U>(andMaybe: Maybe<U>, maybe: Maybe<T>): Maybe<U>;
440export declare function and<T, U>(andMaybe: Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;
441/**
442 Apply a function to the wrapped value if {@linkcode Just} and return a new
443 `Just` containing the resulting value; or return {@linkcode Nothing} if
444 `Nothing`.
445
446 This differs from {@linkcode map} in that `thenFn` returns another `Maybe`.
447 You can use `andThen` to combine two functions which *both* create a `Maybe`
448 from an unwrapped type.
449
450 You may find the `.then` method on an ES6 `Promise` helpful for comparison: if
451 you have a `Promise`, you can pass its `then` method a callback which returns
452 another `Promise`, and the result will not be a *nested* promise, but a single
453 `Promise`. The difference is that `Promise#then` unwraps *all* layers to only
454 ever return a single `Promise` value, whereas `Maybe.andThen` will not unwrap
455 nested `Maybe`s.
456
457 This is sometimes also known as `bind`, but *not* aliased as such because
458 [`bind` already means something in JavaScript][bind].
459
460 [bind]:
461 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
462
463 #### Example
464
465 (This is a somewhat contrived example, but it serves to show the way the
466 function behaves.)
467
468 ```ts
469 import Maybe, { andThen, toString } from 'true-myth/maybe';
470
471 // string -> Maybe<number>
472 const toMaybeLength = (s: string) => Maybe.of(s.length);
473
474 // Maybe<string>
475 const aMaybeString = Maybe.of('Hello, there!');
476
477 // Maybe<number>
478 const resultingLength = andThen(toMaybeLength, aMaybeString);
479 console.log(toString(resultingLength)); // 13
480 ```
481
482 Note that the result is not `Just(Just(13))`, but `Just(13)`!
483
484 @template T The type of the wrapped value.
485 @template U The type of the wrapped value in the resulting `Maybe`.
486 @param thenFn The function to apply to the wrapped `T` if `maybe` is `Just`.
487 @param maybe The `Maybe` to evaluate and possibly apply a function to the
488 contents of.
489 @returns The result of the `thenFn` (a new `Maybe`) if `maybe` is a
490 `Just`, otherwise `Nothing` if `maybe` is a `Nothing`.
491 */
492export declare function andThen<T, U>(thenFn: (t: T) => Maybe<U>, maybe: Maybe<T>): Maybe<U>;
493export declare function andThen<T, U>(thenFn: (t: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;
494/**
495 Provide a fallback for a given {@linkcode Maybe}. Behaves like a logical `or`:
496 if the `maybe` value is a {@linkcode Just}, returns that `maybe`; otherwise,
497 returns the `defaultMaybe` value.
498
499 This is useful when you want to make sure that something which takes a `Maybe`
500 always ends up getting a `Just` variant, by supplying a default value for the
501 case that you currently have a nothing.
502
503 ```ts
504 import Maybe from 'true-utils/maybe';
505
506 const justA = Maybe.just("a");
507 const justB = Maybe.just("b");
508 const aNothing: Maybe<string> = nothing();
509
510 console.log(Maybe.or(justB, justA).toString()); // Just(A)
511 console.log(Maybe.or(aNothing, justA).toString()); // Just(A)
512 console.log(Maybe.or(justB, aNothing).toString()); // Just(B)
513 console.log(Maybe.or(aNothing, aNothing).toString()); // Nothing
514 ```
515
516 @template T The type of the wrapped value.
517 @param defaultMaybe The `Maybe` to use if `maybe` is a `Nothing`.
518 @param maybe The `Maybe` instance to evaluate.
519 @returns `maybe` if it is a `Just`, otherwise `defaultMaybe`.
520 */
521export declare function or<T>(defaultMaybe: Maybe<T>, maybe: Maybe<T>): Maybe<T>;
522export declare function or<T>(defaultMaybe: Maybe<T>): (maybe: Maybe<T>) => Maybe<T>;
523/**
524 Like {@linkcode or}, but using a function to construct the alternative
525 {@linkcode Maybe}.
526
527 Sometimes you need to perform an operation using other data in the environment
528 to construct the fallback value. In these situations, you can pass a function
529 (which may be a closure) as the `elseFn` to generate the fallback `Maybe<T>`.
530
531 Useful for transforming empty scenarios based on values in context.
532
533 @template T The type of the wrapped value.
534 @param elseFn The function to apply if `maybe` is `Nothing`
535 @param maybe The `maybe` to use if it is `Just`.
536 @returns The `maybe` if it is `Just`, or the `Maybe` returned by `elseFn`
537 if the `maybe` is `Nothing`.
538 */
539export declare function orElse<T>(elseFn: () => Maybe<T>, maybe: Maybe<T>): Maybe<T>;
540export declare function orElse<T>(elseFn: () => Maybe<T>): (maybe: Maybe<T>) => Maybe<T>;
541/**
542 Safely get the value out of a {@linkcode Maybe}.
543
544 Returns the content of a {@linkcode Just} or `defaultValue` if
545 {@linkcode Nothing}. This is the recommended way to get a value out of a
546 `Maybe` most of the time.
547
548 ```ts
549 import Maybe from 'true-myth/maybe';
550
551 const notAString = Maybe.nothing<string>();
552 const isAString = Maybe.just('look ma! some characters!');
553
554 console.log(Maybe.unwrapOr('<empty>', notAString)); // "<empty>"
555 console.log(Maybe.unwrapOr('<empty>', isAString)); // "look ma! some characters!"
556 ```
557
558 @template T The type of the wrapped value.
559 @param defaultValue The value to return if `maybe` is a `Nothing`.
560 @param maybe The `Maybe` instance to unwrap if it is a `Just`.
561 @returns The content of `maybe` if it is a `Just`, otherwise
562 `defaultValue`.
563 */
564export declare function unwrapOr<T, U>(defaultValue: U, maybe: Maybe<T>): T | U;
565export declare function unwrapOr<T, U>(defaultValue: U): (maybe: Maybe<T>) => T | U;
566/**
567 Safely get the value out of a {@linkcode Maybe} by returning the wrapped value
568 if it is {@linkcode Just}, or by applying `orElseFn` if it is
569 {@linkcode Nothing}.
570
571 This is useful when you need to *generate* a value (e.g. by using current
572 values in the environment – whether preloaded or by local closure) instead of
573 having a single default value available (as in {@linkcode unwrapOr}).
574
575 ```ts
576 import Maybe from 'true-myth/maybe';
577
578 // You can imagine that someOtherValue might be dynamic.
579 const someOtherValue = 99;
580 const handleNothing = () => someOtherValue;
581
582 const aJust = Maybe.just(42);
583 console.log(Maybe.unwrapOrElse(handleNothing, aJust)); // 42
584
585 const aNothing = nothing<number>();
586 console.log(Maybe.unwrapOrElse(handleNothing, aNothing)); // 99
587 ```
588
589 @template T The wrapped value.
590 @param orElseFn A function used to generate a valid value if `maybe` is a
591 `Nothing`.
592 @param maybe The `Maybe` instance to unwrap if it is a `Just`
593 @returns Either the content of `maybe` or the value returned from
594 `orElseFn`.
595 */
596export declare function unwrapOrElse<T, U>(orElseFn: () => U, maybe: Maybe<T>): T | U;
597export declare function unwrapOrElse<T, U>(orElseFn: () => U): (maybe: Maybe<T>) => T | U;
598/**
599 Create a `String` representation of a {@linkcode Maybe} instance.
600
601 A {@linkcode Just} instance will be `Just(<representation of the value>)`,
602 where the representation of the value is simply the value's own `toString`
603 representation. For example:
604
605 | call | output |
606 |----------------------------------------|-------------------------|
607 | `toString(Maybe.of(42))` | `Just(42)` |
608 | `toString(Maybe.of([1, 2, 3]))` | `Just(1,2,3)` |
609 | `toString(Maybe.of({ an: 'object' }))` | `Just([object Object])` |
610 | `toString(Maybe.nothing())` | `Nothing` |
611
612 @template T The type of the wrapped value; its own `.toString` will be used
613 to print the interior contents of the `Just` variant.
614 @param maybe The value to convert to a string.
615 @returns The string representation of the `Maybe`.
616 */
617export declare function toString<T>(maybe: Maybe<T>): string;
618/**
619 * Create an `Object` representation of a {@linkcode Maybe} instance.
620 *
621 * Useful for serialization. `JSON.stringify()` uses it.
622 *
623 * @param maybe The value to convert to JSON
624 * @returns The JSON representation of the `Maybe`
625 */
626export declare function toJSON<T>(maybe: Maybe<T>): MaybeJSON<unknown>;
627/**
628 A lightweight object defining how to handle each variant of a {@linkcode Maybe}.
629 */
630export type Matcher<T, A> = {
631 Just: (value: T) => A;
632 Nothing: () => A;
633};
634/**
635 Performs the same basic functionality as {@linkcode unwrapOrElse}, but instead
636 of simply unwrapping the value if it is {@linkcode Just} and applying a value
637 to generate the same default type if it is {@linkcode Nothing}, lets you
638 supply functions which may transform the wrapped type if it is `Just` or get a
639 default value for `Nothing`.
640
641 This is kind of like a poor man's version of pattern matching, which
642 JavaScript currently lacks.
643
644 Instead of code like this:
645
646 ```ts
647 import Maybe from 'true-myth/maybe';
648
649 const logValue = (mightBeANumber: Maybe<number>) => {
650 const valueToLog = Maybe.mightBeANumber.isJust
651 ? mightBeANumber.value.toString()
652 : 'Nothing to log.';
653
654 console.log(valueToLog);
655 };
656 ```
657
658 ...we can write code like this:
659
660 ```ts
661 import { match } from 'true-myth/maybe';
662
663 const logValue = (mightBeANumber: Maybe<number>) => {
664 const value = match(
665 {
666 Just: n => n.toString(),
667 Nothing: () => 'Nothing to log.',
668 },
669 mightBeANumber
670 );
671
672 console.log(value);
673 };
674 ```
675
676 This is slightly longer to write, but clearer: the more complex the resulting
677 expression, the hairer it is to understand the ternary. Thus, this is
678 especially convenient for times when there is a complex result, e.g. when
679 rendering part of a React component inline in JSX/TSX.
680
681 @param matcher A lightweight object defining what to do in the case of each
682 variant.
683 @param maybe The `maybe` instance to check.
684 */
685export declare function match<T, A>(matcher: Matcher<T, A>, maybe: Maybe<T>): A;
686export declare function match<T, A>(matcher: Matcher<T, A>): (m: Maybe<T>) => A;
687/**
688 Allows quick triple-equal equality check between the values inside two
689 {@linkcode Maybe maybe} instances without having to unwrap them first.
690
691 ```ts
692 const a = Maybe.of(3);
693 const b = Maybe.of(3);
694 const c = Maybe.of(null);
695 const d = Maybe.nothing();
696
697 Maybe.equals(a, b); // true
698 Maybe.equals(a, c); // false
699 Maybe.equals(c, d); // true
700 ```
701
702 @param mb A `maybe` to compare to.
703 @param ma A `maybe` instance to check.
704 */
705export declare function equals<T>(mb: Maybe<T>, ma: Maybe<T>): boolean;
706export declare function equals<T>(mb: Maybe<T>): (ma: Maybe<T>) => boolean;
707/**
708 Allows you to *apply* (thus `ap`) a value to a function without having to take
709 either out of the context of their {@linkcode Maybe}s. This does mean that the
710 transforming function is itself within a `Maybe`, which can be hard to grok at
711 first but lets you do some very elegant things. For example, `ap` allows you
712 to this:
713
714 ```ts
715 import { just, nothing } from 'true-myth/maybe';
716
717 const one = just(1);
718 const five = just(5);
719 const none = nothing();
720
721 const add = (a: number) => (b: number) => a + b;
722 const maybeAdd = just(add);
723
724 maybeAdd.ap(one).ap(five); // Just(6)
725 maybeAdd.ap(one).ap(none); // Nothing
726 maybeAdd.ap(none).ap(five) // Nothing
727 ```
728
729 Without `ap`, you'd need to do something like a nested `match`:
730
731 ```ts
732 import { just, nothing } from 'true-myth/maybe';
733
734 const one = just(1);
735 const five = just(5);
736 const none = nothing();
737
738 one.match({
739 Just: n => five.match({
740 Just: o => just(n + o),
741 Nothing: () => nothing(),
742 }),
743 Nothing: () => nothing(),
744 }); // Just(6)
745
746 one.match({
747 Just: n => none.match({
748 Just: o => just(n + o),
749 Nothing: () => nothing(),
750 }),
751 Nothing: () => nothing(),
752 }); // Nothing
753
754 none.match({
755 Just: n => five.match({
756 Just: o => just(n + o),
757 Nothing: () => nothing(),
758 }),
759 Nothing: () => nothing(),
760 }); // Nothing
761 ```
762
763 And this kind of thing comes up quite often once you're using `Maybe` to
764 handle optionality throughout your application.
765
766 For another example, imagine you need to compare the equality of two
767 ImmutableJS data structures, where a `===` comparison won't work. With `ap`,
768 that's as simple as this:
769
770 ```ts
771 import Maybe from 'true-myth/maybe';
772 import { is as immutableIs, Set } from 'immutable';
773
774 const is = (first: unknown) => (second: unknown) =>
775 immutableIs(first, second);
776
777 const x = Maybe.of(Set.of(1, 2, 3));
778 const y = Maybe.of(Set.of(2, 3, 4));
779
780 Maybe.of(is).ap(x).ap(y); // Just(false)
781 ```
782
783 Without `ap`, we're back to that gnarly nested `match`:
784
785 ```ts
786 import Maybe, { just, nothing } from 'true-myth/maybe';
787 import { is, Set } from 'immutable';
788
789 const x = Maybe.of(Set.of(1, 2, 3));
790 const y = Maybe.of(Set.of(2, 3, 4));
791
792 x.match({
793 Just: iX => y.match({
794 Just: iY => Maybe.just(is(iX, iY)),
795 Nothing: () => Maybe.nothing(),
796 })
797 Nothing: () => Maybe.nothing(),
798 }); // Just(false)
799 ```
800
801 In summary: anywhere you have two `Maybe` instances and need to perform an
802 operation that uses both of them, `ap` is your friend.
803
804 Two things to note, both regarding *currying*:
805
806 1. All functions passed to `ap` must be curried. That is, they must be of the
807 form (for add) `(a: number) => (b: number) => a + b`, *not* the more usual
808 `(a: number, b: number) => a + b` you see in JavaScript more generally.
809
810 (Unfortunately, these do not currently work with lodash or Ramda's `curry`
811 helper functions. A future update to the type definitions may make that
812 work, but the intermediate types produced by those helpers and the more
813 general function types expected by this function do not currently align.)
814
815 2. You will need to call `ap` as many times as there are arguments to the
816 function you're dealing with. So in the case of this `add3` function,
817 which has the "arity" (function argument count) of 3 (`a` and `b`), you'll
818 need to call `ap` twice: once for `a`, and once for `b`. To see why, let's
819 look at what the result in each phase is:
820
821 ```ts
822 const add3 = (a: number) => (b: number) => (c: number) => a + b + c;
823
824 const maybeAdd = just(add3); // Just((a: number) => (b: number) => (c: number) => a + b + c)
825 const maybeAdd1 = maybeAdd.ap(just(1)); // Just((b: number) => (c: number) => 1 + b + c)
826 const maybeAdd1And2 = maybeAdd1.ap(just(2)) // Just((c: number) => 1 + 2 + c)
827 const final = maybeAdd1.ap(just(3)); // Just(4)
828 ```
829
830 So for `toString`, which just takes a single argument, you would only need
831 to call `ap` once.
832
833 ```ts
834 const toStr = (v: { toString(): string }) => v.toString();
835 just(toStr).ap(12); // Just("12")
836 ```
837
838 One other scenario which doesn't come up *quite* as often but is conceivable
839 is where you have something that may or may not actually construct a function
840 for handling a specific `Maybe` scenario. In that case, you can wrap the
841 possibly-present in `ap` and then wrap the values to apply to the function to
842 in `Maybe` themselves.
843
844 __Aside:__ `ap` is not named `apply` because of the overlap with JavaScript's
845 existing [`apply`] function – and although strictly speaking, there isn't any
846 direct overlap (`Maybe.apply` and `Function.prototype.apply` don't intersect
847 at all) it's useful to have a different name to avoid implying that they're
848 the same.
849
850 [`apply`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
851
852 @param maybeFn maybe a function from T to U
853 @param maybe maybe a T to apply to `fn`
854 */
855export declare function ap<T, U extends {}>(maybeFn: Maybe<(t: T) => U>, maybe: Maybe<T>): Maybe<U>;
856export declare function ap<T, U extends {}>(maybeFn: Maybe<(t: T) => U>): (maybe: Maybe<T>) => Maybe<U>;
857/**
858 Determine whether an item is an instance of {@linkcode Maybe}.
859
860 @param item The item to check.
861 */
862export declare function isInstance<T>(item: unknown): item is Maybe<T>;
863export type Predicate<T> = (element: T, index: number, array: AnyArray<T>) => boolean;
864export type NarrowingPredicate<T, U extends T> = (element: T, index: number, array: AnyArray<T>) => element is U;
865/** An array or a readonly array. */
866export type AnyArray<T> = Array<T> | ReadonlyArray<T>;
867/**
868 Safely search for an element in an array.
869
870 This function behaves like `Array.prototype.find`, but returns `Maybe<T>`
871 instead of `T | undefined`.
872
873 ## Examples
874
875 The basic form is:
876
877 ```ts
878 import Maybe from 'true-myth/maybe';
879
880 let array = [1, 2, 3];
881 Maybe.find(v => v > 1, array); // Just(2)
882 Maybe.find(v => v < 1, array); // Nothing
883 ```
884
885 The function is curried so you can use it in a functional chain. For example
886 (leaving aside error handling on a bad response for simplicity), suppose the
887 url `https://arrays.example.com` returned a JSON payload with the type
888 `Array<{ count: number, name: string }>`, and we wanted to get the first
889 of these where `count` was at least 100. We could write this:
890
891 ```ts
892 import Maybe from 'true-myth/maybe';
893
894 type Item = { count: number; name: string };
895 type Response = Array<Item>;
896
897 // curried variant!
898 const findAtLeast100 = Maybe.find(({ count }: Item) => count > 100);
899
900 fetch('https://arrays.example.com')
901 .then(response => response.json() as Response)
902 .then(findAtLeast100)
903 .then(found => {
904 if (found.isJust) {
905 console.log(`The matching value is ${found.value.name}!`);
906 }
907 });
908 ```
909
910 @param predicate A function to execute on each value in the array, returning
911 `true` when the item in the array matches the condition. The
912 signature for `predicate` is identical to the signature for
913 the first argument to `Array.prototype.find`. The function
914 is called once for each element of the array, in ascending
915 order, until it finds one where predicate returns true. If
916 such an element is found, find immediately returns that
917 element value wrapped in `Just`. Otherwise, `Maybe.find`
918 returns `Nothing`.
919 * @param array The array to search using the predicate.
920 */
921export declare function find<T, U extends T>(predicate: NarrowingPredicate<T, U>, array: AnyArray<T>): Maybe<U>;
922export declare function find<T, U extends T>(predicate: NarrowingPredicate<T, U>): (array: AnyArray<T>) => Maybe<U>;
923export declare function find<T>(predicate: Predicate<T>, array: AnyArray<T>): Maybe<T>;
924export declare function find<T>(predicate: Predicate<T>): (array: AnyArray<T>) => Maybe<T>;
925/**
926 Safely get the first item from a list, returning {@linkcode Just} the first
927 item if the array has at least one item in it, or {@linkcode Nothing} if it is
928 empty.
929
930 ## Examples
931
932 ```ts
933 let empty = [];
934 Maybe.head(empty); // => Nothing
935
936 let full = [1, 2, 3];
937 Maybe.head(full); // => Just(1)
938 ```
939
940 @param array The array to get the first item from.
941 */
942export declare function first<T>(array: AnyArray<T | null | undefined>): Maybe<T>;
943/**
944 Safely get the last item from a list, returning {@linkcode Just} the last item
945 if the array has at least one item in it, or {@linkcode Nothing} if it is
946 empty.
947
948 ## Examples
949
950 ```ts
951 let empty = [];
952 Maybe.last(empty); // => Nothing
953
954 let full = [1, 2, 3];
955 Maybe.last(full); // => Just(3)
956 ```
957
958 @param array The array to get the first item from.
959 */
960export declare function last<T>(array: AnyArray<T | null | undefined>): Maybe<T>;
961/**
962 Given an array or tuple of {@linkcode Maybe}s, return a `Maybe` of the array
963 or tuple values.
964
965 - Given an array of type `Array<Maybe<A> | Maybe<B>>`, the resulting type is
966 `Maybe<Array<A | B>>`.
967 - Given a tuple of type `[Maybe<A>, Maybe<B>]`, the resulting type is
968 `Maybe<[A, B]>`.
969
970 If any of the items in the array or tuple are {@linkcode Nothing}, the whole
971 result is `Nothing`. If all items in the array or tuple are {@linkcode Just},
972 the whole result is `Just`.
973
974 ## Examples
975
976 Given an array with a mix of `Maybe` types in it, both `allJust` and `mixed`
977 here will have the type `Maybe<Array<string | number>>`, but will be `Just`
978 and `Nothing` respectively.
979
980 ```ts
981 import Maybe, { transposeArray } from 'true-myth/maybe';
982
983 let valid = [Maybe.just(2), Maybe.just('three')];
984 let allJust = transposeArray(valid); // => Just([2, 'three']);
985
986 let invalid = [Maybe.just(2), Maybe.nothing<string>()];
987 let mixed = transposeArray(invalid); // => Nothing
988 ```
989
990 When working with a tuple type, the structure of the tuple is preserved. Here,
991 for example, `result` has the type `Maybe<[string, number]>` and will be
992 `Nothing`:
993
994 ```ts
995 import Maybe, { transposeArray } from 'true-myth/maybe';
996
997 type Tuple = [Maybe<string>, Maybe<number>];
998
999 let invalid: Tuple = [Maybe.just('wat'), Maybe.nothing()];
1000 let result = transposeArray(invalid); // => Nothing
1001 ```
1002
1003 If all of the items in the tuple are `Just`, the result is `Just` wrapping the
1004 tuple of the values of the items. Here, for example, `result` again has the
1005 type `Maybe<[string, number]>` and will be `Just(['hey', 12]`:
1006
1007 ```ts
1008 import Maybe, { transposeArray } from 'true-myth/maybe';
1009
1010 type Tuple = [Maybe<string>, Maybe<number>];
1011
1012 let valid: Tuple = [Maybe.just('hey'), Maybe.just(12)];
1013 let result = transposeArray(valid); // => Just(['hey', 12])
1014 ```
1015
1016 __Note:__ this does not work with `ReadonlyArray`. If you have a
1017 `ReadonlyArray` you wish to operate on, you must cast it to `Array` insetad.
1018 This cast is always safe here, because `Array` is a *wider* type than
1019 `ReadonlyArray`.
1020
1021 @param maybes The `Maybe`s to resolve to a single `Maybe`.
1022 */
1023export declare function transposeArray<T extends Array<Maybe<unknown>>>(maybes: T): TransposedArray<T>;
1024export type Unwrapped<T> = T extends Maybe<infer U> ? U : T;
1025export type TransposedArray<T extends Array<Maybe<unknown>>> = Maybe<{
1026 [K in keyof T]: Unwrapped<T[K]>;
1027}>;
1028/**
1029 Safely extract a key from an object, returning {@linkcode Just} if the key has
1030 a value on the object and {@linkcode Nothing} if it does not.
1031
1032 The check is type-safe: you won't even be able to compile if you try to look
1033 up a property that TypeScript *knows* doesn't exist on the object.
1034
1035 ```ts
1036 type Person = { name?: string };
1037
1038 const me: Person = { name: 'Chris' };
1039 console.log(Maybe.property('name', me)); // Just('Chris')
1040
1041 const nobody: Person = {};
1042 console.log(Maybe.property('name', nobody)); // Nothing
1043 ```
1044
1045 However, it also works correctly with dictionary types:
1046
1047 ```ts
1048 type Dict<T> = { [key: string]: T };
1049
1050 const score: Dict<number> = {
1051 player1: 0,
1052 player2: 1
1053 };
1054
1055 console.log(Maybe.property('player1', score)); // Just(0)
1056 console.log(Maybe.property('player2', score)); // Just(1)
1057 console.log(Maybe.property('player3', score)); // Nothing
1058 ```
1059
1060 The order of keys is so that it can be partially applied:
1061
1062 ```ts
1063 type Person = { name?: string };
1064
1065 const lookupName = Maybe.property('name');
1066
1067 const me: Person = { name: 'Chris' };
1068 console.log(lookupName(me)); // Just('Chris')
1069
1070 const nobody: Person = {};
1071 console.log(lookupName(nobody)); // Nothing
1072 ```
1073
1074 @param key The key to pull out of the object.
1075 @param obj The object to look up the key from.
1076 */
1077export declare function property<T, K extends keyof T>(key: K, obj: T): Maybe<NonNullable<T[K]>>;
1078export declare function property<T, K extends keyof T>(key: K): (obj: T) => Maybe<NonNullable<T[K]>>;
1079/**
1080 Safely extract a key from a {@linkcode Maybe} of an object, returning
1081 {@linkcode Just} if the key has a value on the object and
1082 {@linkcode Nothing} if it does not. (Like {@linkcode property} but
1083 operating on a `Maybe<T>` rather than directly on a `T`.)
1084
1085 The check is type-safe: you won't even be able to compile if you try to look
1086 up a property that TypeScript *knows* doesn't exist on the object.
1087
1088 ```ts
1089 import { get, just, nothing } from 'true-myth/maybe';
1090
1091 type Person = { name?: string };
1092
1093 const me: Maybe<Person> = just({ name: 'Chris' });
1094 console.log(get('name', me)); // Just('Chris')
1095
1096 const nobody = nothing<Person>();
1097 console.log(get('name', nobody)); // Nothing
1098 ```
1099
1100 However, it also works correctly with dictionary types:
1101
1102 ```ts
1103 import { get, just } from 'true-myth/maybe';
1104
1105 type Dict<T> = { [key: string]: T };
1106
1107 const score: Maybe<Dict<number>> = just({
1108 player1: 0,
1109 player2: 1
1110 });
1111
1112 console.log(get('player1', score)); // Just(0)
1113 console.log(get('player2', score)); // Just(1)
1114 console.log(get('player3', score)); // Nothing
1115 ```
1116
1117 The order of keys is so that it can be partially applied:
1118
1119 ```ts
1120 import { get, just } from 'true-myth/maybe';
1121
1122 type Person = { name?: string };
1123
1124 const lookupName = get('name');
1125
1126 const me: Person = { name: 'Chris' };
1127 console.log(lookupName(me)); // Just('Chris')
1128
1129 const nobody: Person = {};
1130 console.log(lookupName(nobody)); // Nothing
1131 ```
1132
1133 @param key The key to pull out of the object.
1134 @param maybeObj The object to look up the key from.
1135 */
1136export declare function get<T, K extends keyof T>(key: K, maybeObj: Maybe<T>): Maybe<NonNullable<T[K]>>;
1137export declare function get<T, K extends keyof T>(key: K): (maybeObj: Maybe<T>) => Maybe<NonNullable<T[K]>>;
1138/**
1139 Transform a function from a normal JS function which may return `null` or
1140 `undefined` to a function which returns a {@linkcode Maybe} instead.
1141
1142 For example, dealing with the `Document#querySelector` DOM API involves a
1143 *lot* of things which can be `null`:
1144
1145 ```ts
1146 const foo = document.querySelector('#foo');
1147 let width: number;
1148 if (foo !== null) {
1149 width = foo.getBoundingClientRect().width;
1150 } else {
1151 width = 0;
1152 }
1153
1154 const getStyle = (el: HTMLElement, rule: string) => el.style[rule];
1155 const bar = document.querySelector('.bar');
1156 let color: string;
1157 if (bar != null) {
1158 let possibleColor = getStyle(bar, 'color');
1159 if (possibleColor !== null) {
1160 color = possibleColor;
1161 } else {
1162 color = 'black';
1163 }
1164 }
1165 ```
1166
1167 (Imagine in this example that there were more than two options: the
1168 simplifying workarounds you commonly use to make this terser in JS, like the
1169 ternary operator or the short-circuiting `||` or `??` operators, eventually
1170 become very confusing with more complicated flows.)
1171
1172 We can work around this with `Maybe`, always wrapping each layer in
1173 {@linkcode Maybe.of} invocations, and this is *somewhat* better:
1174
1175 ```ts
1176 import Maybe from 'true-myth/maybe';
1177
1178 const aWidth = Maybe.of(document.querySelector('#foo'))
1179 .map(el => el.getBoundingClientRect().width)
1180 .unwrapOr(0);
1181
1182 const aColor = Maybe.of(document.querySelector('.bar'))
1183 .andThen(el => Maybe.of(getStyle(el, 'color'))
1184 .unwrapOr('black');
1185 ```
1186
1187 With `wrapReturn`, though, you can create a transformed version of a function
1188 *once* and then be able to use it freely throughout your codebase, *always*
1189 getting back a `Maybe`:
1190
1191 ```ts
1192 import { wrapReturn } from 'true-myth/maybe';
1193
1194 const querySelector = wrapReturn(document.querySelector.bind(document));
1195 const safelyGetStyle = wrapReturn(getStyle);
1196
1197 const aWidth = querySelector('#foo')
1198 .map(el => el.getBoundingClientRect().width)
1199 .unwrapOr(0);
1200
1201 const aColor = querySelector('.bar')
1202 .andThen(el => safelyGetStyle(el, 'color'))
1203 .unwrapOr('black');
1204 ```
1205
1206 @param fn The function to transform; the resulting function will have the
1207 exact same signature except for its return type.
1208 */
1209export declare function wrapReturn<F extends AnyFunction, P extends Parameters<F>, R extends NonNullable<ReturnType<F>>>(fn: F): (...args: P) => Maybe<R>;
1210/**
1211 This is the standard *correct* definition for a function which is a proper
1212 subtype of all other functions: parameters of a function subtype must be
1213 *wider* than those of the base type, and return types must be *narrower*.
1214 Everything is wider than `never[]` and narrower than `unknown`, so any
1215 function is assignable to places this is used.
1216 */
1217export type AnyFunction = (...args: never[]) => unknown;
1218/**
1219 The public interface for the {@linkcode Maybe} class *as a value*: a
1220 constructor and the associated static properties.
1221 */
1222export interface MaybeConstructor {
1223 new <T>(value?: T | null | undefined): Maybe<T>;
1224 of: typeof MaybeImpl.of;
1225 just: typeof MaybeImpl.just;
1226 nothing: typeof MaybeImpl.nothing;
1227}
1228/** A value which may ({@linkcode Just `Just<T>`}) or may not
1229 * ({@linkcode Nothing}) be present. */
1230export type Maybe<T> = Just<T> | Nothing<T>;
1231export declare const Maybe: MaybeConstructor;
1232export default Maybe;
1233//# sourceMappingURL=maybe.d.ts.map
\No newline at end of file