-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheither.ts
More file actions
60 lines (44 loc) · 1.64 KB
/
either.ts
File metadata and controls
60 lines (44 loc) · 1.64 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
import { Box2, Kind, Type } from 'data/kind'
export type Left<T> = () => NonNullable<T>
export type Right<T> = () => NonNullable<T>
export type Either<TL, TR> = Left<TL> | Right<TR>
export type EitherBox<T1, T2> = Box2<T1, T2> & Either<T1, T2>
type InnerEither<TL, TR> = Left<TL> &
Right<TR> & {
from: 'Left' | 'Right'
}
type Case<TL, TR, K> = {
left?: NonNullable<(_: TL) => K>
right?: NonNullable<(_: TR) => K>
}
export const kindOf =
<TL, TR>(_: Either<TL, TR>): Kind =>
(_: '*') =>
(_: '*') =>
'*' as Type
const createResult = <T>(value: NonNullable<T>, from: 'Left' | 'Right') => {
const result = () => value
result.from = from
result.kind = (_: '*') => (_: '*') => '*' as Type
return result
}
export const left = <TL, TR = unknown>(value: NonNullable<TL>): EitherBox<TL, TR> => createResult<TL>(value, 'Left')
export const right = <TL, TR>(value: NonNullable<TR>): EitherBox<TL, TR> => createResult<TR>(value, 'Right')
export const $case =
<TL, TR, K>(caseOf: Case<TL, TR, K>) =>
(either: Either<TL, TR> | EitherBox<TL, TR>): K => {
const _either = either as InnerEither<TL, TR>
if (_either.from === 'Left') {
if (!caseOf.left) {
throw new Error('Non-exhaustive patterns for Left')
}
return caseOf.left((either as Left<TL>)())
}
if (_either.from === 'Right') {
if (!caseOf.right) {
throw new Error('Non-exhaustive patterns for Right')
}
return caseOf.right((either as Right<TR>)())
}
throw new Error('Non-exhaustive patterns')
}