nalloc 0.0.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -8
- package/build/iter.cjs +6 -8
- package/build/iter.cjs.map +1 -1
- package/build/iter.js +6 -8
- package/build/iter.js.map +1 -1
- package/build/option.cjs +16 -8
- package/build/option.cjs.map +1 -1
- package/build/option.d.ts +12 -2
- package/build/option.js +13 -8
- package/build/option.js.map +1 -1
- package/build/result.cjs +102 -24
- package/build/result.cjs.map +1 -1
- package/build/result.d.ts +96 -14
- package/build/result.js +87 -21
- package/build/result.js.map +1 -1
- package/build/safe.cjs +16 -0
- package/build/safe.cjs.map +1 -1
- package/build/safe.d.ts +22 -1
- package/build/safe.js +8 -1
- package/build/safe.js.map +1 -1
- package/build/types.cjs +2 -2
- package/build/types.cjs.map +1 -1
- package/build/types.d.ts +1 -0
- package/build/types.js +2 -2
- package/build/types.js.map +1 -1
- package/package.json +29 -10
- package/src/__tests__/index.ts +34 -0
- package/src/__tests__/option.ts +23 -1
- package/src/__tests__/option.types.ts +2 -1
- package/src/__tests__/result.ts +194 -1
- package/src/__tests__/result.types.ts +18 -5
- package/src/iter.ts +4 -2
- package/src/option.ts +23 -7
- package/src/result.ts +188 -37
- package/src/safe.ts +49 -1
- package/src/types.ts +4 -2
package/src/result.ts
CHANGED
|
@@ -4,6 +4,9 @@ import type { Ok, Err, Result, Option, Widen, WidenNever, MaybePromise } from '.
|
|
|
4
4
|
export type { Ok, Err, Result };
|
|
5
5
|
export { isOk, isErr };
|
|
6
6
|
|
|
7
|
+
const identity = <T>(v: T): T => v;
|
|
8
|
+
const wrapErr = (error: unknown): Err<never> => ERR(error) as Err<never>;
|
|
9
|
+
|
|
7
10
|
/**
|
|
8
11
|
* Executes a function and captures the result or error.
|
|
9
12
|
* @param fn - Function to execute
|
|
@@ -14,8 +17,11 @@ export { isOk, isErr };
|
|
|
14
17
|
* tryCatch(() => JSON.parse('invalid')) // Err(SyntaxError)
|
|
15
18
|
* tryCatch(() => { throw 'oops' }, e => e) // Err('oops')
|
|
16
19
|
*/
|
|
17
|
-
export function tryCatch<T>(fn: () => T): Result<T, unknown>;
|
|
18
|
-
export function tryCatch<T, E>(
|
|
20
|
+
export function tryCatch<T>(fn: () => T): T extends Err<any> ? Err<unknown> : T extends Result<infer U, any> ? Result<U, unknown> : Result<T, unknown>;
|
|
21
|
+
export function tryCatch<T, E>(
|
|
22
|
+
fn: () => T,
|
|
23
|
+
onError: (error: unknown) => E,
|
|
24
|
+
): T extends Err<infer F> ? Err<F | E> : T extends Result<infer U, infer F> ? Result<U, F | E> : Result<T, E>;
|
|
19
25
|
export function tryCatch<T, E = unknown>(fn: () => T, onError?: (error: unknown) => E): Result<T, E> {
|
|
20
26
|
try {
|
|
21
27
|
return fn() as Ok<T>;
|
|
@@ -29,8 +35,55 @@ export function tryCatch<T, E = unknown>(fn: () => T, onError?: (error: unknown)
|
|
|
29
35
|
* @param fn - Function to execute
|
|
30
36
|
* @returns Ok(result) if successful, Err(error) if thrown
|
|
31
37
|
*/
|
|
38
|
+
export function of<T>(fn: () => T): T extends Err<any> ? Err<unknown> : T extends Result<infer U, any> ? Result<U, unknown> : Result<T, unknown>;
|
|
32
39
|
export function of<T>(fn: () => T): Result<T, unknown> {
|
|
33
|
-
|
|
40
|
+
try {
|
|
41
|
+
return fn() as Ok<T>;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
return ERR(error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Wraps a throwing function so it returns a Result instead.
|
|
49
|
+
* The wrapper is created once and reused, avoiding per-call closure allocation.
|
|
50
|
+
* @param fn - The function to wrap
|
|
51
|
+
* @param onError - Optional error transformer
|
|
52
|
+
* @returns A new function with the same signature that returns Result
|
|
53
|
+
* @example
|
|
54
|
+
* const safeParse = wrap(JSON.parse);
|
|
55
|
+
* safeParse('{"a":1}') // Ok({a: 1})
|
|
56
|
+
* safeParse('invalid') // Err(SyntaxError)
|
|
57
|
+
*/
|
|
58
|
+
export function wrap<A extends unknown[], R>(fn: (...args: A) => R): (...args: A) => Result<R, unknown>;
|
|
59
|
+
export function wrap<A extends unknown[], R, E>(fn: (...args: A) => R, onError: (error: unknown) => E): (...args: A) => Result<R, E>;
|
|
60
|
+
export function wrap<A extends unknown[], R, E = unknown>(fn: (...args: A) => R, onError?: (error: unknown) => E): (...args: A) => Result<R, E> {
|
|
61
|
+
return (...args: A) => {
|
|
62
|
+
try {
|
|
63
|
+
return fn(...args) as Ok<R>;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
return ERR(onError ? onError(error) : (error as E));
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Converts a Result-returning function into a throwing function.
|
|
72
|
+
* Inverse of wrap. Use at ecosystem boundaries where libraries expect exceptions
|
|
73
|
+
* (Express error handlers, Drizzle transactions, Passport.js, etc.).
|
|
74
|
+
* @param fn - A function that returns a Result
|
|
75
|
+
* @returns A new function that returns the Ok value or throws the Err error
|
|
76
|
+
* @example
|
|
77
|
+
* const findUser = (id: string): Result<User, NotFoundError> => { ... };
|
|
78
|
+
* const throwingFind = toThrowable(findUser);
|
|
79
|
+
* throwingFind('123') // returns User or throws NotFoundError
|
|
80
|
+
*/
|
|
81
|
+
export function toThrowable<A extends unknown[], R, E>(fn: (...args: A) => Result<R, E>): (...args: A) => R {
|
|
82
|
+
return (...args: A) => {
|
|
83
|
+
const result = fn(...args);
|
|
84
|
+
if (isErr(result)) throw result.error;
|
|
85
|
+
return result;
|
|
86
|
+
};
|
|
34
87
|
}
|
|
35
88
|
|
|
36
89
|
/**
|
|
@@ -42,8 +95,8 @@ export function of<T>(fn: () => T): Result<T, unknown> {
|
|
|
42
95
|
* await fromPromise(fetch('/api')) // Ok(Response) or Err(unknown)
|
|
43
96
|
* await fromPromise(fetch('/api'), e => String(e)) // Ok(Response) or Err(string)
|
|
44
97
|
*/
|
|
45
|
-
export async function fromPromise<T>(promise: Promise<T
|
|
46
|
-
export async function fromPromise<T, E>(promise: Promise<T
|
|
98
|
+
export async function fromPromise<T>(promise: Promise<Exclude<T, Err<any>>>): Promise<Result<T, unknown>>;
|
|
99
|
+
export async function fromPromise<T, E>(promise: Promise<Exclude<T, Err<any>>>, onError: (error: unknown) => E): Promise<Result<T, E>>;
|
|
47
100
|
export async function fromPromise<T, E = unknown>(promise: Promise<T>, onError?: (error: unknown) => E): Promise<Result<T, E>> {
|
|
48
101
|
try {
|
|
49
102
|
return (await promise) as Ok<T>;
|
|
@@ -52,6 +105,43 @@ export async function fromPromise<T, E = unknown>(promise: Promise<T>, onError?:
|
|
|
52
105
|
}
|
|
53
106
|
}
|
|
54
107
|
|
|
108
|
+
/** A validation issue from a Standard Schema validator. */
|
|
109
|
+
export interface SchemaIssue {
|
|
110
|
+
readonly message: string;
|
|
111
|
+
readonly path?: ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Minimal Standard Schema v1 interface (duck-typed, no external dependency). */
|
|
115
|
+
export interface StandardSchema<O = unknown> {
|
|
116
|
+
readonly '~standard': {
|
|
117
|
+
readonly validate: (value: unknown) => StandardSchemaResult<O> | Promise<StandardSchemaResult<O>>;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type StandardSchemaResult<O> = { readonly value: O; readonly issues?: undefined } | { readonly issues: ReadonlyArray<SchemaIssue> };
|
|
122
|
+
|
|
123
|
+
function schemaResultToResult<O>(sr: StandardSchemaResult<O>): Result<O, readonly SchemaIssue[]> {
|
|
124
|
+
return sr.issues ? ERR(sr.issues) : (sr.value as Ok<O>);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Validates a value against a Standard Schema and returns a Result.
|
|
129
|
+
* Works with any Standard Schema v1 compliant library (Zod, Valibot, ArkType, etc.).
|
|
130
|
+
* Returns synchronously if the schema validates synchronously.
|
|
131
|
+
* @param schema - A Standard Schema v1 compliant schema
|
|
132
|
+
* @param value - The value to validate
|
|
133
|
+
* @returns Ok(parsed) if valid, Err(issues) if invalid
|
|
134
|
+
* @example
|
|
135
|
+
* import { z } from 'zod';
|
|
136
|
+
* const result = fromSchema(z.string().email(), input);
|
|
137
|
+
* // Result<string, readonly SchemaIssue[]>
|
|
138
|
+
*/
|
|
139
|
+
export function fromSchema<O>(schema: StandardSchema<O>, value: unknown): Result<O, readonly SchemaIssue[]> | Promise<Result<O, readonly SchemaIssue[]>> {
|
|
140
|
+
const sr = schema['~standard'].validate(value);
|
|
141
|
+
if (isThenable(sr)) return sr.then(schemaResultToResult);
|
|
142
|
+
return schemaResultToResult(sr);
|
|
143
|
+
}
|
|
144
|
+
|
|
55
145
|
/**
|
|
56
146
|
* Executes a function that may return sync or async, preserving sync execution when possible.
|
|
57
147
|
* @param fn - Function that may return T or Promise<T>
|
|
@@ -118,7 +208,7 @@ export function assertOk<T, E>(result: Result<T, E>, message?: string): asserts
|
|
|
118
208
|
*/
|
|
119
209
|
export function assertErr<T, E>(result: Result<T, E>, message?: string): asserts result is Err<E> {
|
|
120
210
|
if (isOk(result)) {
|
|
121
|
-
throw new Error(message ??
|
|
211
|
+
throw new Error(message ?? `Expected Err result. Received value: ${String(result)}`);
|
|
122
212
|
}
|
|
123
213
|
}
|
|
124
214
|
|
|
@@ -188,11 +278,7 @@ export function flatMap<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<
|
|
|
188
278
|
* @param fn - Function returning a Result
|
|
189
279
|
* @returns The result of fn(value) if Ok, Err unchanged
|
|
190
280
|
*/
|
|
191
|
-
export
|
|
192
|
-
export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
|
|
193
|
-
export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {
|
|
194
|
-
return isErr(result) ? result : fn(result);
|
|
195
|
-
}
|
|
281
|
+
export const andThen: typeof flatMap = flatMap;
|
|
196
282
|
|
|
197
283
|
/**
|
|
198
284
|
* Executes a side effect if Ok, then returns the original Result.
|
|
@@ -501,7 +587,8 @@ export function partition<T, E>(results: Result<T, E>[]): [T[], E[]] {
|
|
|
501
587
|
const oks: T[] = [];
|
|
502
588
|
const errs: E[] = [];
|
|
503
589
|
|
|
504
|
-
for (
|
|
590
|
+
for (let i = 0; i < results.length; i++) {
|
|
591
|
+
const result = results[i];
|
|
505
592
|
if (isOk(result)) {
|
|
506
593
|
oks.push(result);
|
|
507
594
|
} else {
|
|
@@ -513,30 +600,32 @@ export function partition<T, E>(results: Result<T, E>[]): [T[], E[]] {
|
|
|
513
600
|
}
|
|
514
601
|
|
|
515
602
|
/**
|
|
516
|
-
* Extracts all Ok values from an
|
|
517
|
-
* @param results -
|
|
603
|
+
* Extracts all Ok values from an array of Results.
|
|
604
|
+
* @param results - Array of Results
|
|
518
605
|
* @returns Array of Ok values
|
|
519
606
|
* @example
|
|
520
607
|
* filterOk([ok(1), err('a'), ok(2)]) // [1, 2]
|
|
521
608
|
*/
|
|
522
|
-
export function filterOk<T, E>(results:
|
|
609
|
+
export function filterOk<T, E>(results: Result<T, E>[]): T[] {
|
|
523
610
|
const oks: T[] = [];
|
|
524
|
-
for (
|
|
611
|
+
for (let i = 0; i < results.length; i++) {
|
|
612
|
+
const result = results[i];
|
|
525
613
|
if (isOk(result)) oks.push(result);
|
|
526
614
|
}
|
|
527
615
|
return oks;
|
|
528
616
|
}
|
|
529
617
|
|
|
530
618
|
/**
|
|
531
|
-
* Extracts all Err values from an
|
|
532
|
-
* @param results -
|
|
619
|
+
* Extracts all Err values from an array of Results.
|
|
620
|
+
* @param results - Array of Results
|
|
533
621
|
* @returns Array of error values
|
|
534
622
|
* @example
|
|
535
623
|
* filterErr([ok(1), err('a'), ok(2)]) // ['a']
|
|
536
624
|
*/
|
|
537
|
-
export function filterErr<T, E>(results:
|
|
625
|
+
export function filterErr<T, E>(results: Result<T, E>[]): E[] {
|
|
538
626
|
const errs: E[] = [];
|
|
539
|
-
for (
|
|
627
|
+
for (let i = 0; i < results.length; i++) {
|
|
628
|
+
const result = results[i];
|
|
540
629
|
if (isErr(result)) errs.push(result.error);
|
|
541
630
|
}
|
|
542
631
|
return errs;
|
|
@@ -553,7 +642,8 @@ export function filterErr<T, E>(results: Iterable<Result<T, E>>): E[] {
|
|
|
553
642
|
export function collect<T, E>(results: Result<T, E>[]): Result<T[], E> {
|
|
554
643
|
const values: T[] = [];
|
|
555
644
|
|
|
556
|
-
for (
|
|
645
|
+
for (let i = 0; i < results.length; i++) {
|
|
646
|
+
const result = results[i];
|
|
557
647
|
if (isErr(result)) return result;
|
|
558
648
|
values.push(result);
|
|
559
649
|
}
|
|
@@ -572,7 +662,8 @@ export function collect<T, E>(results: Result<T, E>[]): Result<T[], E> {
|
|
|
572
662
|
export function collectAll<T, E>(results: Result<T, E>[]): Result<T[], E[]> {
|
|
573
663
|
const oks: T[] = [];
|
|
574
664
|
const errs: E[] = [];
|
|
575
|
-
for (
|
|
665
|
+
for (let i = 0; i < results.length; i++) {
|
|
666
|
+
const result = results[i];
|
|
576
667
|
if (isOk(result)) {
|
|
577
668
|
oks.push(result);
|
|
578
669
|
} else {
|
|
@@ -653,11 +744,6 @@ export function isErrAnd<T, E>(result: Result<T, E>, predicate: (error: E) => bo
|
|
|
653
744
|
return isErr(result) && predicate(result.error);
|
|
654
745
|
}
|
|
655
746
|
|
|
656
|
-
export function settledToResult<T, E>(result: PromiseSettledResult<Result<T, E>>): Result<T, E> {
|
|
657
|
-
if (result.status === 'fulfilled') return result.value;
|
|
658
|
-
return ERR(result.reason);
|
|
659
|
-
}
|
|
660
|
-
|
|
661
747
|
/**
|
|
662
748
|
* Partitions an async iterable of Results.
|
|
663
749
|
* @param results - Iterable of Promise Results
|
|
@@ -668,7 +754,26 @@ export function settledToResult<T, E>(result: PromiseSettledResult<Result<T, E>>
|
|
|
668
754
|
*/
|
|
669
755
|
export async function partitionAsync<T, E>(promises: Iterable<Promise<Result<T, E>>>): Promise<[Widen<T>[], WidenNever<E>[]]> {
|
|
670
756
|
const settled = await Promise.allSettled(promises);
|
|
671
|
-
|
|
757
|
+
const oks: Widen<T>[] = [];
|
|
758
|
+
const errs: WidenNever<E>[] = [];
|
|
759
|
+
|
|
760
|
+
for (let i = 0; i < settled.length; i++) {
|
|
761
|
+
const entry = settled[i];
|
|
762
|
+
|
|
763
|
+
if (entry.status === 'rejected') {
|
|
764
|
+
errs.push(entry.reason as WidenNever<E>);
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
const result = entry.value;
|
|
769
|
+
if (isOk(result)) {
|
|
770
|
+
oks.push(result as Widen<T>);
|
|
771
|
+
} else {
|
|
772
|
+
errs.push(result.error as WidenNever<E>);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
return [oks, errs];
|
|
672
777
|
}
|
|
673
778
|
|
|
674
779
|
/**
|
|
@@ -683,7 +788,7 @@ export async function partitionAsync<T, E>(promises: Iterable<Promise<Result<T,
|
|
|
683
788
|
*/
|
|
684
789
|
export function settleMaybePromise<T, E = unknown>(values: MaybePromise<T>[]): Result<T, E>[] | Promise<Result<T, E>[]> {
|
|
685
790
|
const len = values.length;
|
|
686
|
-
const results = new Array<Result<T, E>>(len);
|
|
791
|
+
const results = new Array<Result<T, E>>(len).fill(0 as never);
|
|
687
792
|
let pendingIndices: number[] | undefined;
|
|
688
793
|
let pendingPromises: Promise<T>[] | undefined;
|
|
689
794
|
|
|
@@ -714,18 +819,15 @@ export async function partitionMaybePromiseAsync<T, E>(
|
|
|
714
819
|
errs: WidenNever<E>[],
|
|
715
820
|
startIndex: number = 0,
|
|
716
821
|
): Promise<[Widen<T>[], WidenNever<E>[]]> {
|
|
717
|
-
const
|
|
718
|
-
const
|
|
822
|
+
const remaining = values.length - startIndex;
|
|
823
|
+
const promises = new Array<Promise<Result<T, E>>>(remaining).fill(0 as never);
|
|
719
824
|
|
|
720
|
-
for (let i = 0; i <
|
|
825
|
+
for (let i = 0; i < remaining; i++) {
|
|
721
826
|
const value = values[startIndex + i];
|
|
722
|
-
|
|
723
|
-
(result) => result as Result<T, E>,
|
|
724
|
-
(error) => ERR(error as E),
|
|
725
|
-
);
|
|
827
|
+
promises[i] = isThenable(value) ? Promise.resolve(value).then(identity, wrapErr) : Promise.resolve(value);
|
|
726
828
|
}
|
|
727
829
|
|
|
728
|
-
const resolved = await Promise.all(
|
|
830
|
+
const resolved = await Promise.all(promises);
|
|
729
831
|
for (let i = 0; i < resolved.length; i++) {
|
|
730
832
|
const result = resolved[i];
|
|
731
833
|
if (isOk(result)) {
|
|
@@ -734,6 +836,7 @@ export async function partitionMaybePromiseAsync<T, E>(
|
|
|
734
836
|
errs.push((result as Err<WidenNever<E>>).error);
|
|
735
837
|
}
|
|
736
838
|
}
|
|
839
|
+
|
|
737
840
|
return [oks, errs] as [Widen<T>[], WidenNever<E>[]];
|
|
738
841
|
}
|
|
739
842
|
|
|
@@ -804,3 +907,51 @@ export async function safeTryAsync<T>(fn: () => Promise<T>): Promise<Result<T, u
|
|
|
804
907
|
return ERR(e);
|
|
805
908
|
}
|
|
806
909
|
}
|
|
910
|
+
|
|
911
|
+
function* unwrapYield<T, E>(result: Result<T, E>): Generator<Err<E>, T> {
|
|
912
|
+
if (isErr(result)) {
|
|
913
|
+
yield result;
|
|
914
|
+
return undefined as never;
|
|
915
|
+
}
|
|
916
|
+
return result;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
type Unwrapper = <T, E>(result: Result<T, E>) => Generator<Err<E>, T>;
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Generator-based do-notation for Result. Provides a `$` function that unwraps
|
|
923
|
+
* Results inside a generator, short-circuiting on the first Err.
|
|
924
|
+
* Preserves error types (unlike safeTry which erases to unknown).
|
|
925
|
+
* @param fn - Generator function receiving `$` unwrapper
|
|
926
|
+
* @returns Ok(return value) or the first Err encountered
|
|
927
|
+
* @example
|
|
928
|
+
* const result = gen(function*($) {
|
|
929
|
+
* const a = yield* $(parseNumber('10'));
|
|
930
|
+
* const b = yield* $(parseNumber('5'));
|
|
931
|
+
* return a + b;
|
|
932
|
+
* }); // Result<number, ParseError>
|
|
933
|
+
*/
|
|
934
|
+
export function gen<E, T>(fn: ($: Unwrapper) => Generator<Err<E>, T>): Result<T, E> {
|
|
935
|
+
const iter = fn(unwrapYield);
|
|
936
|
+
const step = iter.next();
|
|
937
|
+
if (!step.done) return step.value;
|
|
938
|
+
return step.value as Ok<T>;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* Async generator-based do-notation for Result. Like gen, but for async operations.
|
|
943
|
+
* @param fn - Async generator function receiving `$` unwrapper
|
|
944
|
+
* @returns Promise of Ok(return value) or the first Err encountered
|
|
945
|
+
* @example
|
|
946
|
+
* const result = await genAsync(async function*($) {
|
|
947
|
+
* const user = yield* $(await fetchUser(id));
|
|
948
|
+
* const posts = yield* $(await fetchPosts(user.id));
|
|
949
|
+
* return { user, posts };
|
|
950
|
+
* }); // Promise<Result<{user, posts}, FetchError>>
|
|
951
|
+
*/
|
|
952
|
+
export async function genAsync<E, T>(fn: ($: Unwrapper) => AsyncGenerator<Err<E>, T>): Promise<Result<T, E>> {
|
|
953
|
+
const iter = fn(unwrapYield);
|
|
954
|
+
const step = await iter.next();
|
|
955
|
+
if (!step.done) return step.value;
|
|
956
|
+
return step.value as Ok<T>;
|
|
957
|
+
}
|
package/src/safe.ts
CHANGED
|
@@ -15,7 +15,55 @@ export type {
|
|
|
15
15
|
InferErr,
|
|
16
16
|
MaybePromise,
|
|
17
17
|
} from './types.js';
|
|
18
|
-
export { safeTry, safeTryAsync, unwrap } from './result.js';
|
|
18
|
+
export { safeTry, safeTryAsync, unwrap, gen, genAsync } from './result.js';
|
|
19
19
|
export * as Option from './option.js';
|
|
20
20
|
export * as Result from './result.js';
|
|
21
21
|
export * as Iter from './iter.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Threads a value through a sequence of unary functions, left to right.
|
|
25
|
+
* @param value - The initial value
|
|
26
|
+
* @param fns - Functions to apply in order
|
|
27
|
+
* @returns The result of applying all functions
|
|
28
|
+
* @example
|
|
29
|
+
* pipe(
|
|
30
|
+
* Result.tryCatch(() => JSON.parse(input)),
|
|
31
|
+
* r => Result.flatMap(r, validate),
|
|
32
|
+
* r => Result.map(r, transform),
|
|
33
|
+
* )
|
|
34
|
+
*/
|
|
35
|
+
export function pipe<A>(a: A): A;
|
|
36
|
+
export function pipe<A, B>(a: A, ab: (a: A) => B): B;
|
|
37
|
+
export function pipe<A, B, C>(a: A, ab: (a: A) => B, bc: (b: B) => C): C;
|
|
38
|
+
export function pipe<A, B, C, D>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D;
|
|
39
|
+
export function pipe<A, B, C, D, E>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): E;
|
|
40
|
+
export function pipe<A, B, C, D, E, F>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F): F;
|
|
41
|
+
export function pipe<A, B, C, D, E, F, G>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G): G;
|
|
42
|
+
export function pipe<A, B, C, D, E, F, G, H>(
|
|
43
|
+
a: A,
|
|
44
|
+
ab: (a: A) => B,
|
|
45
|
+
bc: (b: B) => C,
|
|
46
|
+
cd: (c: C) => D,
|
|
47
|
+
de: (d: D) => E,
|
|
48
|
+
ef: (e: E) => F,
|
|
49
|
+
fg: (f: F) => G,
|
|
50
|
+
gh: (g: G) => H,
|
|
51
|
+
): H;
|
|
52
|
+
export function pipe<A, B, C, D, E, F, G, H, I>(
|
|
53
|
+
a: A,
|
|
54
|
+
ab: (a: A) => B,
|
|
55
|
+
bc: (b: B) => C,
|
|
56
|
+
cd: (c: C) => D,
|
|
57
|
+
de: (d: D) => E,
|
|
58
|
+
ef: (e: E) => F,
|
|
59
|
+
fg: (f: F) => G,
|
|
60
|
+
gh: (g: G) => H,
|
|
61
|
+
hi: (h: H) => I,
|
|
62
|
+
): I;
|
|
63
|
+
export function pipe(a: unknown, ...fns: ((v: unknown) => unknown)[]): unknown {
|
|
64
|
+
let result = a;
|
|
65
|
+
for (let i = 0; i < fns.length; i++) {
|
|
66
|
+
result = fns[i](result);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -28,6 +28,8 @@ export type Some<T> = ValueType<T> & { readonly [SOME_BRAND]: true };
|
|
|
28
28
|
/** Represents the absence of a value (null or undefined). */
|
|
29
29
|
export type None = NoneValueType & { readonly [SOME_BRAND]: false };
|
|
30
30
|
|
|
31
|
+
export type UnOption<V, T extends Option<V>> = T extends Some<V> ? V : None;
|
|
32
|
+
|
|
31
33
|
/** Constant representing None. Use this instead of null/undefined for clarity. */
|
|
32
34
|
export const NONE = undefined as None;
|
|
33
35
|
|
|
@@ -226,7 +228,7 @@ export type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;
|
|
|
226
228
|
* @returns true if value is a PromiseLike
|
|
227
229
|
*/
|
|
228
230
|
export function isThenable<T>(value: MaybePromise<T>): value is PromiseLike<T> {
|
|
229
|
-
return typeof (value as PromiseLike<T>)
|
|
231
|
+
return (typeof value === 'object' || typeof value === 'function') && value !== null && typeof (value as PromiseLike<T>).then === 'function';
|
|
230
232
|
}
|
|
231
233
|
|
|
232
234
|
/**
|
|
@@ -235,5 +237,5 @@ export function isThenable<T>(value: MaybePromise<T>): value is PromiseLike<T> {
|
|
|
235
237
|
* @returns true if value is not a PromiseLike
|
|
236
238
|
*/
|
|
237
239
|
export function isSync<T>(value: MaybePromise<T>): value is T {
|
|
238
|
-
return typeof (value as PromiseLike<T>)
|
|
240
|
+
return !(typeof value === 'object' || typeof value === 'function') || value === null || typeof (value as PromiseLike<T>).then !== 'function';
|
|
239
241
|
}
|