Skip to content

Instantly share code, notes, and snippets.

@stylemistake
Created September 15, 2022 06:09
Show Gist options
  • Save stylemistake/d151e26de021a3afca33125abb1c1047 to your computer and use it in GitHub Desktop.
Save stylemistake/d151e26de021a3afca33125abb1c1047 to your computer and use it in GitHub Desktop.
Loadable
enum LoadableStates {
Initial = 'initial',
Loading = 'loading',
Error = 'error',
Value = 'value',
}
type LoadableInitial = Loadable & {
readonly state: LoadableStates.Initial;
};
type LoadableLoading = Loadable & {
readonly state: LoadableStates.Loading;
};
type LoadableValue<T = any, E = any> = Loadable<T, E> & {
readonly state: LoadableStates.Value;
readonly value: T;
};
type LoadableError<T = any, E = any> = Loadable<T, E> & {
readonly state: LoadableStates.Error;
readonly value: E;
};
export class Loadable<T = any, E = any> {
/** Represents a value that has not been initialized. */
static initial = new Loadable(LoadableStates.Initial) as LoadableInitial;
/** Represents a state of loading. */
static loading = new Loadable(LoadableStates.Loading) as LoadableLoading;
/** Represents a loading error. Error object is optional. */
static error(): LoadableError;
static error<E>(error: E): LoadableError<any, E>;
static error<E>(error?: E) {
return new Loadable<any, E>(LoadableStates.Error, error);
}
/** Represents a successfully loaded value. Value itself is optional, though. */
static value(): LoadableValue;
static value<T>(value: T): LoadableValue<T>;
static value<T>(value?: T) {
return new Loadable<T>(LoadableStates.Value, value);
}
readonly state;
readonly value?: T;
readonly error?: E;
private constructor(state: LoadableStates, contents?: any) {
// Need to explicitly set the values in the constructor due to bugs in the TS compiler in storybook
this.state = state;
if (state === LoadableStates.Value) {
this.value = contents;
}
else if (state === LoadableStates.Error) {
this.error = contents;
}
}
isInitial(): this is LoadableInitial {
return this.state === LoadableStates.Initial;
}
isLoading(): this is LoadableLoading {
return this.state === LoadableStates.Loading;
}
isError(): this is LoadableError<T, E> {
return this.state === LoadableStates.Error;
}
isValue(): this is LoadableValue<T, E> {
return this.state === LoadableStates.Value;
}
isDone(): boolean {
return this.isValue() || this.isError();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment