Last active
January 6, 2020 06:22
-
-
Save janwirth/c42889d60588e449dcbac138b7f617c7 to your computer and use it in GitHub Desktop.
JS Remote Data Type with Typescript Typings
This file contains hidden or 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
// Example: RemoteData<HttpError, VehicleList> | |
export type RemoteData<E, D> = NotAsked | Loading | Failure<E> | Success<D>; | |
// Example: RemoteDataMatchers<HttpError, VehicleList> | |
export interface RemoteDataMatchers<E, D, R> { | |
NotAsked: () => R; | |
Loading: () => R; | |
Failure: (E) => R; | |
Success: (D) => R; | |
} | |
export const notAsked: RemoteData<F, D>; | |
export const loading: RemoteData<F, D>; | |
export function success<F, D>(data: D): RemoteData<F, D>; | |
export function failure<F, D>(err: F): RemoteData<F, D>; | |
export type NotAsked = { | |
type: "NotAsked"; | |
}; | |
export type Loading = { | |
type: "Loading"; | |
}; | |
export type Failure<E> = { | |
type: "Failure"; | |
error: E; | |
}; | |
export type Success<D> = { | |
type: "Success"; | |
data: D; | |
}; | |
declare function match<E, D, R>( | |
matchers: RemoteDataMatchers<E, D, R> | |
): (remoteData: RemoteData<E, D>) => any; | |
declare function map<E, D>( | |
fn: (D) => D_ | |
): (remoteData: RemoteData<E, D>) => RemoteData<E, D_>; | |
declare function isSuccess(rd: RemoteData<E, D>): boolean; | |
declare function isLoading(rd: RemoteData<E, D>): boolean; | |
declare function isFailure(rd: RemoteData<E, D>): boolean; |
This file contains hidden or 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
/** | |
* @typedef {import('./RemoteData').RemoteData<E, D>} RemoteData<E, D> | |
* @template E, D | |
*/ | |
/** | |
* @typedef {import('./RemoteData').RemoteDataMatchers<E, D, R>} RemoteDataMatchers<E, D, R> | |
* @template E, D, R | |
*/ | |
/** | |
* This function takes an object with a property of each state that remote data can be in. | |
* The corresping function will be called depending on what type of remmote data we pass in. | |
* @param {RemoteDataMatchers<E, D, R>} matchers | |
* @returns (remoteData: RemoteData<E,D,R>): R | |
* @template E, D, R | |
*/ | |
export const match = matchers => remoteData => { | |
switch (remoteData.type) { | |
case "NotAsked": | |
return matchers.NotAsked(); | |
case "Loading": | |
return matchers.Loading(); | |
case "Failure": | |
return matchers.Failure(remoteData.err); | |
case "Success": | |
return matchers.Success(remoteData.data); | |
default: | |
return matchers.Loading(); | |
} | |
}; | |
export const map = fn => remoteData => { | |
switch (remoteData.type) { | |
case "Success": | |
return success(fn(remoteData.data)); | |
default: | |
return remoteData; | |
} | |
}; | |
/** | |
* @type RemoteData<E, D> | |
* @template E, D | |
*/ | |
export const notAsked = { type: "NotAsked" }; | |
/** | |
* @type RemoteData<E, D> | |
* @template E, D | |
*/ | |
export const loading = { type: "Loading" }; | |
/** | |
* @param {E} err | |
* @returns RemoteData<E, D> | |
* @template E, D | |
*/ | |
export const failure = err => ({ type: "Failure", err }); | |
/** | |
* @param {D} data | |
* @returns RemoteData<E, D> | |
* @template E, D | |
*/ | |
export const success = data => ({ type: "Success", data }); | |
/** | |
* @param {RemoteData<E, D>} rd | |
* @returns boolean | |
*/ | |
export const isSuccess = rd => rd.type === "Success"; | |
/** | |
* @param {RemoteData<E, D>} rd | |
* @returns boolean | |
*/ | |
export const isLoading = rd => rd.type === "Loading"; | |
/** | |
* @param {RemoteData<E, D>} rd | |
* @returns boolean | |
*/ | |
export const isFailure = rd => rd.type === "Failure"; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment