Giter VIP home page Giter VIP logo

srd's Introduction

npm SRD License License

๐Ÿš€ Simple Remote Data

Simple Remote Data (SRD) is a fully static land compliant implementation of the Remote Data type in TypeScript - built with Higer Kinded Types (HKT's) inspired by fp-ts and Elm Remote Data.

The idea for using HKT's in TypeScript is based on Lightweight higher-kinded polymorphism.

Static Land Compliant

Install

With yarn

yarn add srd

or if you prefer npm

npm i srd

or if you don't like bundlers, no need to install, just import directly from a CDN:

<script type="module">
  import { SRD } from 'https://cdn.skypack.dev/srd';
</script>

SRD supports CJS, UMD and ESM bundle outputs.

Examples

React Example

import React, { useState, useEffect } from 'react'
import { SRD, notAsked, loading, failure, success } from 'srd'

const App = () => {
  const [rd, setRd] = useState(notAsked())

  useEffect(() => {
    setRd(loading())
    fetch('...')
      .then((data) => setRd(success(data)))
      .catch((err) => setRd(failure(err)))
  }, [])

  return SRD.match({
    notAsked: () => <div>Empty</div>,
    loading: () => <div>Loading...</div>,
    failure: (err) => <div>{err}</div>,
    success: (data) => <div>{data}</div>,
  }, rd)
}

Typescript React Example

SRD works even better with Typescript! Declare your RD type once and have typescript powerfully infer it everywhere! Like magic!

import React, { useState, useEffect } from 'react'
import { SRD, RD, notAsked, loading, failure, success } from 'srd'
import { Person, getPerson } from './people'

const App = () => {
  const [rd, setRd] = useState<RD<string, Person>>(notAsked())

  useEffect(() => {
    setRd(loading())
    getPerson(123)
      .then((person) => setRd(success(person)))
      .catch((err) => setRd(failure(err)))
  }, [])

  return SRD.match({
    notAsked: () => <div>Empty</div>,
    loading: () => <div>Loading...</div>,
    failure: (msg) => <div>{msg}</div>,
    success: (person) => <div>{person}</div>,
  }, rd)
}

Documentation

SRD comes with many of the Static Land functions that we all know and love. Here is a breakdown of all the supported algebras and utilities:

Setoid

For comparing 2 SRD's to see if they are the same type.

*Note: This only compares the data types and not the inner value. So Success(5) != Failure(5) but Success(5) == Success(80).

equals :: (RD e a, RD e b) -> boolean
import { SRD, success, notAsked } from 'SRD'

SRD.equals(success(5), notAsked()) // false

Functor

Allowing the SRD to be mapped over by the function provided.

map :: (a -> b, RD e a) -> RD e b
import { SRD, success, loading } from 'SRD'

const double = x => x * 2
const rd1 = success(4)
const rd2 = loading()

SRD.map(double, rd1) // success(8)
SRD.map(double, rd2) // loading()

Bifunctor

Allowing the type to be bimapped over by the functions provided. Common usecase is for when you need to map and mapFailure in one shot.

bimap :: (e -> b, a -> c, RD e a) -> RD b c
import { SRD, success, failure } from 'SRD'

const double = x => x * 2
const formatErr = err => `Something went wrong: ${err}`
const rd1 = success(4)
const rd2 = failure('404 not found')

SRD.bimap(formatErr, double, rd1) // success(8)
SRD.bimap(formatErr, double, rd2) // failure('Something went wrong: 404 not found')

Apply

Apply a function wrapped in a SRD to a value wrapped in a SRD.

ap :: (RD e (a -> b), RD e a) -> RD e b
import { SRD, success, failure } from 'SRD'

const double = x => x * 2
const formatErr = err => `Something went wrong: ${err}`
const rd1 = success(4)
const rd2 = failure('404 not found')

SRD.ap(success(double), rd1)) // success(8)
SRD.ap(success(double), rd2)) // failure('404 not found')

Applicative

Always returns a success with whatever value is passed within.

of :: a -> RD e a
import { SRD } from 'SRD'

SRD.of(4) // success(4)

Alt

Provide a default value to be returned when an SRD is not a success type.

alt :: (RD e a, RD e a) -> RD e a
import { SRD, success, loading, notAsked } from 'SRD'

SRD.alt(success(4), notAsked())  // success(4)
SRD.alt(success(50), success(4)) // success(4)
SRD.alt(loading(), notAsked())   // loading()
SRD.alt(loading(), success(4))   // success(4)

Chain

Similar to map but the callback must return another SRD.

chain :: (a -> RD e b, RD e a) -> RD e b
import { SRD, success, failure, notAsked } from 'SRD'

SRD.chain(x => success(x * 2), success(4))    // success(8)
SRD.chain(x => success(x * 2), notAsked())    // notAsked()
SRD.chain(x => failure('failed'), success(4)) // failure('failed')

Match

Provide a mapper object for each SRD type and whichever type the SRD is - that function will run.

data Matcher e a ::
  { notAsked :: () -> c
  , loading :: () -> c
  , failure :: e -> c
  , success :: a -> c
  }

match :: (Matcher e a -> c, RD e a) -> c
import { SRD, success } from 'SRD'

SRD.match({
  notAsked: () => 'Empty',
  loading: () => 'Loading...',
  failure: e => `Err: ${e}`,
  success: data => `My data is ${data}`
}, success(4)) // My data is 4

Map Failure

Similar to map but instead of running the callback on a success, it calls it on a failure.

mapFailure :: (e -> b, RD e a) -> RD b a
import { SRD, success, failure } from 'SRD'

SRD.mapFailure(x => `hello ${x}`, success(4))     // success(4)
SRD.mapFailure(x => `hello ${x}`, failure('bob')) // failure('hello bob')

Map2

Similar to map but takes 2 SRD's instead of one, and if both are a success, the provided callback will be called.

map2 :: (a b -> c, RD e a, RD e b) -> RD e c
import { SRD, success, failure } from 'SRD'

SRD.map2((x, y) => x + y, success(4), success(8))     // success(12)
SRD.map2((x, y) => x + y, failure('bob'), success(8)) // failure('bob')
SRD.map2((x, y) => x + y, success(8), failure('bob')) // failure('bob')

Map3

Similar to map2 but takes 3 SRD's instead of two, and if all three are a success, the provided callback will be called.

map3 :: (a b c -> d, RD e a, RD e b, RD e c) -> RD e d
import { SRD, success, failure, notAsked, loading } from 'SRD'

const add3 = (x, y, z) = x + y + z

SRD.map3(add3, success(4), success(8), success(10))    // success(22)
SRD.map3(add3, failure('bob'), success(8), notAsked()) // failure('bob')
SRD.map3(add3, success(8), loading(), failure('bob'))  // loading()

Unwrap

Similar to alt, but unwraps the SRD from it's type and runs the callback on it. If the SRD is a success the inner value is passed to the callback and returned, any other value the default is returned.

unwrap :: (b, a -> b, RD e a) -> b
import { SRD, success, notAsked, loading } from 'SRD'

const double = x => x * 2

SRD.unwrap(6, double, success(8)) // 16
SRD.unwrap(6, double, notAsked()) // 6
SRD.unwrap(6, double, loading())  // 6

Unpack

Similar to unwrap, but takes a default thunk instead of a default value.

unpack :: (() -> b, a -> b, RD e a) -> b
import { SRD, success, notAsked, loading } from 'SRD'

const double = x => x * 2

SRD.unpack(() => 6, double, success(8)) // 16
SRD.unpack(() => 6, double, notAsked()) // 6
SRD.unpack(() => 6, double, loading())  // 6

WithDefault

Takes a default value and an SRD. If the SRD is a success then the inner value is returned, otherwise the default value is returned.

withDefault :: (a, RD e a) -> a
import { SRD, success, notAsked, loading } from 'SRD'

SRD.withDefault(4, success(8)) // 8
SRD.withDefault(4, notAsked()) // 4
SRD.withDefault(4, loading())  // 4

IsSuccess

Takes an SRD and returns a boolean if it is a success type.

isSuccess :: (RD e a) -> bool
import { SRD, success, notAsked } from 'SRD'

SRD.isSuccess(success(8)) // true
SRD.isSuccess(notAsked()) // false

IsFailure

Takes an SRD and returns a boolean if it is a failure type.

isFailure :: (RD e a) -> bool
import { SRD, success, failure } from 'SRD'

SRD.isFailure(success(8)) // false
SRD.isFailure(failure())  // true

IsNotAsked

Takes an SRD and returns a boolean if it is a notAsked type.

isNotAsked :: (RD e a) -> bool
import { SRD, success, notAsked } from 'SRD'

SRD.isNotAsked(success(8)) // false
SRD.isNotAsked(notAsked()) // true

IsLoading

Takes an SRD and returns a boolean if it is a loading type.

isLoading :: (RD e a) -> bool
import { SRD, success, loading } from 'SRD'

SRD.isLoading(success(8)) // false
SRD.isLoading(loading())  // true

srd's People

Contributors

rametta avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.