-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathresult.ts
More file actions
330 lines (274 loc) · 7.91 KB
/
result.ts
File metadata and controls
330 lines (274 loc) · 7.91 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
import { None, Option, Some } from './option';
import { ToString } from './utils';
interface BaseResult<O, E extends ToString> {
/**
* Returns true if the result is `Ok`.
*
* @returns boolean
*/
isOk(): this is Ok<O>;
/**
* Returns `true` if the result is `Ok` and the value inside of it matches
* a predicate.
*
* @param fn Predicate to match.
* @returns boolean
*/
isOkAnd(fn: (value: Readonly<O>) => boolean): this is Ok<O>;
/**
* Returns `true` if the result is `Err`.
*
* @returns boolean
*/
isErr(): this is Err<E>;
/**
* Returns `true` if the result is `Err` and the value inside of it matches
* a predicate.
*
* @param fn Predicate to match.
* @returns boolean
*/
isErrAnd(fn: (error: Readonly<E>) => boolean): this is Err<E>;
match<T, K>(matcher: {
ok: (value: Readonly<O>) => T;
err: (error: Readonly<E>) => K;
}): T | K;
/**
* Returns the contained `Ok` value.
*
* Because this function may throw, its use is generally discouraged. Instead,
* prefer to use pattern matching and handle the `Err` case explicitly, or
* call `unwrap_or` or `unwrap_or_else`.
*
* @returns The contained `Ok` value.
*
* @throws Throws if the value is an `Err`, with a panic message provided by
* the `Err`'s value.
*/
unwrap(): O;
/**
* Returns the contained `Err` value.
*
* @returns The contained `Err` value.
*
* @throws Throws if the value is an `Ok`, with a custom panic message
* provided by the `Ok`'s value.
*/
unwrapErr(): E;
/**
* Returns the contained `Ok` value or a provided default.
*
* @param defaultValue The default value if `Err`.
* @returns Either contained `Ok` value of default value.
*/
unwrapOr(defaultValue: O): O;
/**
* Returns the contained `Ok` value or computes it from a closure.
*
* @param fn Computed the default value if `Err`.
* @returns The contained `Ok` value or computed default value.
*/
unwrapOrElse(fn: (error: Readonly<E>) => O): O;
/**
* Converts from `Result<O, E>` to `Option<O>`. Converts self into an
* `Option<O>` and discarding the error, if any.
*
* @returns The converted option.
*/
ok(): Option<O>;
/**
* Converts from `Result<O, E>` to `Option<E>`. Converts self into an
* `Option<E>` and discarding the success value, if any.
*
* @returns The converted option.
*/
err(): Option<E>;
/**
* Maps a `Result<O, E>` to `Result<T, E>` by applying a function to a
* contained `Ok` value, leaving an `Err` value untouched.
*
* This function can be used to compose the results of two functions.
*
* @param fn The mapping function.
* @returns The mapped result.
*/
map<T extends ToString>(fn: (value: Readonly<O>) => T): Result<T, E>;
/**
* Returns the provided default (if `Err`), or applies a function to the
* contained value (if `Ok`).
*
* @param defaultValue The default value of `Err`.
* @param fn The mapping function if `Ok`.
* @returns The mapped result.
*/
mapOr<T>(defaultValue: T, fn: (value: Readonly<O>) => T): T;
/**
* Maps a `Result<O, E>` to `T` by applying fallback function default to a
* contained `Err` value, or function `fn` to a contained `Ok` value.
*
* This function can be used to unpack a successful result while handling
* an error.
*
* @param defaultFn Function computing the default value if `Err`.
* @param fn Mapping function if `Ok`.
* @returns The mapped value.
*/
mapOrElse<T>(
defaultFn: (error: Readonly<E>) => T,
fn: (value: Readonly<O>) => T,
): T;
/**
* Maps a `Result<O, E>` to `Result<O, F>` by applying a function to a
* contained `Err` value, leaving an `Ok` value untouched.
*
* This function can be used to pass through a successful result while
* handling an error.
*
* @param fn Error mapping function.
* @returns The mapped result.
*/
mapErr<T extends ToString>(fn: (error: Readonly<E>) => T): Result<O, T>;
/**
* Returns the contained `Ok` value.
*
* Because this function may throw, its use is generally discouraged. Instead,
* prefer to use pattern matching and handle the `Err` case explicitly, or
* call `unwrap_or` or `unwrap_or_else`.
*
* @param message Error message.
* @returns The contained `Ok` value.
*
* @throws Throws if the value is an `Err`, with a panic message including the
* passed message, and the content of the `Err`.
*/
expect(message: string): O;
/**
* Returns the contained `Err` value.
*
* @param message Error message.
* @returns The contained `Err` value.
*
* @throws Throws if the value is an `Ok`, with an error message including the
* passed message, and the content of the `Ok`.
*/
expectErr(message: string): E;
}
export class OkImpl<O> implements BaseResult<O, never> {
constructor(public value: O) {}
isOk(): this is Ok<O> {
return true;
}
isOkAnd(fn: (value: Readonly<O>) => boolean): this is Ok<O> {
return fn(this.value);
}
isErr(): this is Err<never> {
return false;
}
isErrAnd(_fn: (error: Readonly<never>) => boolean): this is Err<never> {
return false;
}
match<T>(matcher: { ok: (value: Readonly<O>) => T }): T {
return matcher.ok(this.value);
}
unwrap(): O {
return this.value;
}
unwrapErr(): never {
return this.expectErr('called `Result.unwrapErr()` on an `Ok` value');
}
unwrapOr(_defaultValue: O): O {
return this.value;
}
unwrapOrElse(_fn: (error: Readonly<never>) => O): O {
return this.value;
}
ok(): Option<O> {
return Some(this.value);
}
err(): None {
return None;
}
map<T extends ToString>(fn: (value: Readonly<O>) => T): Result<T, never> {
return Ok(fn(this.value));
}
mapOr<T>(_defaultValue: T, fn: (value: Readonly<O>) => T): T {
return fn(this.value);
}
mapOrElse<T>(
_defaultFn: (error: Readonly<never>) => T,
fn: (value: Readonly<O>) => T,
): T {
return fn(this.value);
}
mapErr<T extends ToString>(_fn: (error: Readonly<never>) => T): Result<O, T> {
return Ok(this.value);
}
expect(_message: string): O {
return this.value;
}
expectErr(message: string): never {
throw new Error(`${message}`);
}
}
export const Ok = <O>(value: O) => new OkImpl(value);
export type Ok<O> = OkImpl<O>;
class ErrImpl<E extends ToString> implements BaseResult<never, E> {
constructor(public error: E) {}
isOk(): this is Ok<never> {
return false;
}
isOkAnd(_fn: (value: never) => boolean): this is Ok<never> {
return false;
}
isErr(): this is Err<E> {
return true;
}
isErrAnd(fn: (error: Readonly<E>) => boolean): this is Err<E> {
return fn(this.error);
}
match<T, K>(matcher: { err: (error: Readonly<E>) => K }): T | K {
return matcher.err(this.error);
}
unwrap(): never {
return this.expect('called `Result.unwrap()` on an `Err` value');
}
unwrapErr(): E {
return this.error;
}
unwrapOr<T>(defaultValue: T): T {
return defaultValue;
}
unwrapOrElse<T>(fn: (error: Readonly<E>) => T): T {
return fn(this.error);
}
ok(): Option<never> {
return None;
}
err(): Option<E> {
return Some(this.error);
}
map<T extends ToString>(_fn: (value: never) => T): Result<never, E> {
return Err(this.error);
}
mapOr<T>(defaultValue: T, _fn: (value: never) => T): T {
return defaultValue;
}
mapOrElse<T>(
defaultFn: (error: Readonly<E>) => T,
_fn: (value: never) => T,
): T {
return defaultFn(this.error);
}
mapErr<T extends ToString>(fn: (error: Readonly<E>) => T): Result<never, T> {
return Err(fn(this.error));
}
expect(message: string): never {
throw new Error(`${message}`);
}
expectErr(_message: string): E {
return this.error;
}
}
export const Err = <E extends ToString>(error: E) => new ErrImpl(error);
export type Err<E extends ToString> = ErrImpl<E>;
export type Result<O, E extends ToString> = Ok<O> | Err<E>;