This is a port of the RemoteData type from Kris Jenkins article „How Elm Slays a UI Antipattern“ to TypeScript with TsMonad. There have been ports to Flow and JavaScript as well.
Last active
August 17, 2018 10:15
-
-
Save bfncs/4d4977483393315d4f3bf42d7cc43091 to your computer and use it in GitHub Desktop.
Slaying a UI Antipattern with TypeScript & TsMonad
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Monad, Functor, Eq, eq } from 'tsmonad'; | |
export enum RemoteDataType { NotAsked, Loading, Failure, Success } | |
export interface RemoteDataPatterns<E, D, T> { | |
notAsked: () => T; | |
loading: () => T; | |
failure: (l: E) => T; | |
success: (r: D) => T; | |
} | |
export default class RemoteData<E, D> implements Monad<D>, Functor<D>, Eq<RemoteData<E, D>> { | |
of = this.unit; | |
chain = this.bind; | |
lift = this.fmap; | |
map = this.fmap; | |
static notAsked<E, D>() { | |
return new RemoteData<E, D>(RemoteDataType.NotAsked); | |
} | |
static loading<E, D>() { | |
return new RemoteData<E, D>(RemoteDataType.Loading); | |
} | |
static failure<E, D>(error: E) { | |
return new RemoteData<E, D>(RemoteDataType.Failure, error); | |
} | |
static success<E, D>(data: D) { | |
return new RemoteData<E, D>(RemoteDataType.Success, undefined, data); | |
} | |
constructor(private type: RemoteDataType, private error?: E, private data?: D) {} | |
unit<T>(t: T) { | |
return RemoteData.success<E, T>(t); | |
} | |
bind<T>(f: (d: D) => RemoteData<E, T>) { | |
switch (this.type) { | |
case RemoteDataType.NotAsked: | |
return RemoteData.notAsked<E, T>(); | |
case RemoteDataType.Loading: | |
return RemoteData.loading<E, T>(); | |
case RemoteDataType.Failure: | |
return RemoteData.failure<E, T>(this.error as E); | |
case RemoteDataType.Success: | |
default: | |
return f(this.data as D); | |
} | |
} | |
fmap<T>(f: (d: D) => T) { | |
return this.bind(v => this.unit<T>(f(v))); | |
} | |
caseOf<T>(pattern: RemoteDataPatterns<E, D, T>) { | |
switch (this.type) { | |
case RemoteDataType.NotAsked: | |
return pattern.notAsked(); | |
case RemoteDataType.Loading: | |
return pattern.loading(); | |
case RemoteDataType.Failure: | |
return pattern.failure(this.error as E); | |
case RemoteDataType.Success: | |
default: | |
return pattern.success(this.data as D); | |
} | |
} | |
equals(other: RemoteData<E, D>) { | |
if (other.type !== this.type) { | |
return false; | |
} | |
switch (this.type) { | |
case RemoteDataType.NotAsked: | |
case RemoteDataType.Loading: | |
return true; | |
case RemoteDataType.Failure: | |
return eq(this.error, other.error); | |
case RemoteDataType.Success: | |
default: | |
return eq(this.data, other.data); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment