-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoption.ts
More file actions
76 lines (62 loc) · 1.7 KB
/
option.ts
File metadata and controls
76 lines (62 loc) · 1.7 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
export type OptionExpression<T> = Generator<Option<T> | T, Option<T> | T, T>
export abstract class Option<T> {
constructor(protected _value: T) {}
isSome(): this is Some<T> {
return this instanceof Some
}
isNone(): this is None {
return !this.isSome()
}
map<K>(mapper: (value: T) => K): Option<K> {
return this.isSome() ? new Some(mapper(this._value)) : new None()
}
bind<K>(binder: (value: T) => Option<K>): Option<K> {
return this.isSome() ? binder(this._value) : new None()
}
then<K>(thenner: (value: T) => K | Option<K>): Option<K> {
if (this.isSome()) {
const result = thenner(this._value)
return result instanceof Option ? result : new Some(result)
} else {
return new None()
}
}
defaultWith(value: T): T {
return this.isSome() ? this.value : value
}
static from<T>(value: T): Option<T> {
return value == undefined ? new None() : new Some(value)
}
static eval<T>(expression: () => OptionExpression<T>): Option<T> {
const iterable = expression()
let { value, done } = iterable.next()
while (!done) {
if (!(value instanceof Option)) {
const r = iterable.next(value)
value = r.value
done = r.done
} else if (value.isSome()) {
const r = iterable.next(value.value)
value = r.value
done = r.done
} else {
iterable.return(new None())
done = true
}
}
return value instanceof Option ? value : new Some(value)
}
}
export class Some<T> extends Option<T> {
constructor(value: T) {
super(value)
}
get value(): T {
return this._value
}
}
export class None extends Option<never> {
constructor() {
super(null!)
}
}