-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheither.ts
More file actions
114 lines (103 loc) · 2.85 KB
/
either.ts
File metadata and controls
114 lines (103 loc) · 2.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
* @description `Either` Sum Type
*/
type Either<L, R> = Left<L> | Right<R>;
/**
* @description `Left<L>` interface. The Left constructor is used to provide an error feedback about the computation.
* If we return a `Left<L>` from a computation that `may` fail, we will comunicate to the consumer that the computation did not happen successfully.
*/
interface Left<L> {
readonly _tag: "Left";
readonly left: L;
}
/**
* @description `Right<R>` interface. The Right constructor is used to provide a success feedback about the computation.
* If we return a `Right<R>` from a computation that `may` fail, we will comunicate to the consumer that the computation did happen successfully.
*/
interface Right<R> {
readonly _tag: "Right";
readonly right: R;
}
/**
* @description The `Right<R>` constructor.
* @category Constructors
*/
const Right = <R>(v: R): Right<R> =>
({
_tag: "Right",
right: v,
} as const);
/**
* @description The `Left<L>` constructor.
* @category Constructors
*/
const Left = <L>(v: L): Left<L> =>
({
_tag: "Left",
left: v,
} as const);
/**
* @description Predicate to check wheter the current Either is a Right
* @category Predicates
*/
const isRight = <L, R>(e: Either<L, R>): e is Right<R> =>
e._tag === "Right";
/**
* @description Predicate to check wheter the current Either is a Left
* @category Predicates
*/
const isLeft = <L, R>(e: Either<L, R>): e is Left<L> => e._tag === "Left";
/**
* @description Curried implementation of map. Maps the `Right<R>` channel with a given function.
* @category Transformations
*/
const map =
<L, R, R1>(fn: (e: R) => R1) =>
(e: Either<L, R>): Either<L, R1> => {
if (isLeft(e)) return e;
const computation = fn(e.right);
return Right(computation);
};
/**
* @description Curried implementation of mapLeft. Maps the `Left<L>` channel with a given function.
* @category Transformations
*/
const mapLeft =
<L, R, L1>(fn: (e: L) => L1) =>
(e: Either<L, R>): Either<L1, R> => {
if (isRight(e)) return e;
const computation = fn(e.left);
return Left(computation);
};
/**
* @description Curried implementation of flatMap. Maps the `Right<R>` channel with a given function that returns an Either.
* @category Transformations
*/
const flatMap =
<L, R, R1>(fn: (e: R) => Either<L, R1>) =>
(either: Either<L, R>) => {
if (isLeft(either)) return either;
return fn(either.right);
};
/**
* @description utility function to handle the end of the Either chain with a callback for the `Left` case and one for the `Right` case.
* @category Unwrappers
*/
const match =
<L, R, L1, R1>(matcher: {
onLeft: (l: L) => L1;
onRight: (r: R) => R1;
}) =>
(e: Either<L, R>): L1 | R1 =>
isLeft(e) ? matcher.onLeft(e.left) : matcher.onRight(e.right);
export {
Either,
Right,
Left,
isLeft,
isRight,
map,
mapLeft,
match,
flatMap,
};