-
Notifications
You must be signed in to change notification settings - Fork 0
/
result.ts
129 lines (117 loc) · 3.91 KB
/
result.ts
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { DefaultOrFunc, getDefault } from "./fn"
import { None, Maybe, Voidable, isNone } from "./maybe"
import { UnionToIntersection } from "./types"
/** Means success */
export interface Ok<T> { res: T }
/** Means failure */
export interface Err<E> { err: E }
/** Union of success or failure
* ```ts
* type Result<T, E> = Ok<T> | Err<E>
* ```
*/
export type Result<T, E> = Ok<T> | Err<E>
/** Make a `Ok<T>` */
export function ok<T>(res: T): Ok<T> {
return { res }
}
/** Make a `Err<E>` */
export function err<E>(err: E): Err<E> {
return { err }
}
/** Check value is `OK<T>` */
export function isOk<T>(v?: any): v is Ok<T> {
return typeof v === 'object' && v !== null && 'res' in v
}
/** Check value is `Err<E>` */
export function isErr<E>(v?: any): v is Err<E> {
return typeof v === 'object' && v !== null && 'err' in v
}
/** Check value is `Result<T, E>` */
export function isResult<T, E>(v?: any): v is Result<T, E> {
return typeof v === 'object' && v !== null && ('res' in v || 'err' in v)
}
/** Get `T` in `Ok<T>` */
export function getOk<T>(v: Ok<T>): T
/** Get nothing */
export function getOk<E>(v: Err<E>): undefined
/** Get `T` in `Result<T, E>` */
export function getOk<T, E>(v: Result<T, E>): Voidable<T>
/** Get nothing */
export function getOk<T, E>(v?: undefined): undefined
/** Get nothing */
export function getOk<T, E>(v?: null): null
/** Get nothing */
export function getOk<T, E>(v?: None): None
/** Get `T` in `Result<T, E>` */
export function getOk<T, E>(v?: Maybe<Result<T, E>>): Voidable<T>
export function getOk<T, E>(v?: Maybe<Result<T, E>>): Voidable<T> {
return (v as any).res
}
/** Get `E` in `Err<E>` */
export function getErr<E>(v: Err<E>): E
/** Get nothing */
export function getErr<T>(v: Ok<T>): undefined
/** Get `E` in `Result<T, E>` */
export function getErr<T, E>(v: Result<T, E>): Voidable<E>
/** Get nothing */
export function getErr<T, E>(v?: undefined): undefined
/** Get nothing */
export function getErr<T, E>(v?: null): null
/** Get nothing */
export function getErr<T, E>(v?: None): None
/** Get `E` in `Result<T, E>` */
export function getErr<T, E>(v?: Maybe<Result<T, E>>): Voidable<E>
export function getErr<T, E>(v?: Maybe<Result<T, E>>): Voidable<E> {
return (v as any).err
}
export function mapOk<T, E, U>(v: Result<T, E>, f: (val: T) => U): Result<U, E> {
if (isOk(v)) {
return ok(f(getOk(v)))
} else return v
}
export function mapErr<T, E, U>(v: Result<T, E>, f: (val: E) => U): Result<T, U> {
if (isErr(v)) {
return err(f(getErr(v)))
} else return v
}
export namespace Result {
export function and<T, E, U>(v: Result<T, E>, o: DefaultOrFunc<Result<U, E>>): Result<U, E> {
if (isErr(v)) return v
return getDefault(o)
}
export function or<T, E>(v: Result<T, E>, o: DefaultOrFunc<Result<T, E>>): Result<T, E> {
if (isErr(v)) return getDefault(o)
return v
}
/** Transpose Result to Maybe */
export function transpose<T, E>(v: Result<Maybe<T>, E>): Voidable<Result<T, E>> {
if (isOk(v)) {
if (isNone(getOk(v))) return
return v as Result<T, E>
}
return v
}
type NestedOk<T> = Ok<T> | Ok<NestedOk<T>>
type NestedResult<T, E> = Result<T, E> | Ok<NestedResult<T, E>>
type FlattenResult<N> = N extends NestedOk<infer T> ? FlattenResult<T> : N extends Err<any> ? N : Ok<N>
/** Flatten result
*
* ## Example
* ```ts
* let a: Result<1, 2> = flatten<Result<Result<Result<1, 2>, 2>, 2>>(ok(ok(ok(1))))
* let b: Ok<1> = flatten<Ok<Ok<Ok<1>>>>(ok(ok(ok(1))))
* let c: Err<2> = flatten<Ok<Ok<Err<2>>>>(ok(ok(err(2))))
* ```
*/
export function flatten<N extends NestedResult<any, any>>(v: N): FlattenResult<N> {
while (isOk(v)) {
if (isResult(v.res)) {
v = v.res as any
} else {
return v as any
}
}
return v as any
}
}