aboutsummaryrefslogtreecommitdiff
path: root/frontend/ts/src/lib/loadable.ts
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/ts/src/lib/loadable.ts')
-rw-r--r--frontend/ts/src/lib/loadable.ts73
1 files changed, 73 insertions, 0 deletions
diff --git a/frontend/ts/src/lib/loadable.ts b/frontend/ts/src/lib/loadable.ts
new file mode 100644
index 0000000..919e0ba
--- /dev/null
+++ b/frontend/ts/src/lib/loadable.ts
@@ -0,0 +1,73 @@
+export type Loadable<T> = Init | Loading | Loaded<T> | Failure
+
+type Init = {
+ key: 'INIT'
+}
+
+export const init: Init = { key: 'INIT' }
+
+export function isInit(l: Loadable<any>): l is Init {
+ return l.key == 'INIT'
+}
+
+type Loading = {
+ key: 'LOADING'
+}
+
+export const loading: Loading = { key: 'LOADING' }
+
+export function isLoading(l: Loadable<any>): l is Loading {
+ return l.key == 'LOADING'
+}
+
+type Loaded<T> = {
+ key: 'LOADED',
+ value: T
+}
+
+export function loaded<T>(value: T): Loaded<T> {
+ return { key: 'LOADED', value }
+}
+
+export function isLoaded<T>(l: Loadable<T>): l is Loaded<T> {
+ return l.key == 'LOADED'
+}
+
+type Failure = {
+ key: 'FAILURE',
+ error: string
+}
+
+export function failure(error: string): Failure {
+ return {
+ key: 'FAILURE',
+ error
+ }
+}
+
+export function isFailure(l: Loadable<any>): l is Failure {
+ return l.key == 'FAILURE'
+}
+
+export function map<A, B>(loadable: Loadable<A>, f: (value: A) => B): Loadable<B> {
+ if (loadable.key == 'LOADED') {
+ return loaded(f(loadable.value))
+ } else {
+ return loadable
+ }
+}
+
+export function map2<A, B, C>(l: [Loadable<A>, Loadable<B>], f: (a: A, b: B) => C): Loadable<C> {
+ const [l1, l2] = l
+ if (l1.key == 'FAILURE') {
+ return l1
+ } else if (l2.key == 'FAILURE') {
+ return l2
+ } else if (l1.key == 'LOADING' || l2.key == 'LOADING') {
+ return loading
+ } else if (l1.key == 'INIT' || l2.key == 'INIT') {
+ return init
+ } else {
+ return loaded(f(l1.value, l2.value))
+ }
+}