npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@throned/resource-ts

v0.1.2

Published

## Install

Downloads

36

Readme

throned ▲ resource-ts

Install

npm install --save @throned/resource-ts

yarn add @throned/resource-ts

Also it plays nicely with fp-ts pipe function, so if you wish yarn add fp-ts.

Intro

Resource is an ADT (Algebraic Data Type), that is heavily inspired by RemoteData from Slaying a UI antipattern articles.

Simply put, Resource is representation of some asynchronous data in type-safe way that also allows you to drop boolean flags such as isLoading, error etc.

Resource<D, E> is a sum type of four possible states: Initial, Loading, Success<D> and Failure<E>, where D - is a type of data and E - is a type of possible error.

When your resource is in Initial or Loading state it holds no data, so just use initial and loading constants. But Success holds some data and Failure holds the error, so for them you need to use success or failure function depending on result.

import {initial, loading, success, failure} from '@throned/resource-ts'

initial // {tag: 'initial'}
loading // {tag: 'loading'}
success({result: 'Blade Runner'}) // {tag: 'success', value: {result: 'Blade Runner'}}
failure(new Error('noop')) // {tag: 'failure', error: Error('nope')}

The proccess of wrapping your data into Resource called lifting. So when you do const resource = success(await res.json()) - you lift your response in Resource.

So now, when your data is lifted, we can do different type-safe manipulations with it using functions from @throned/resource-ts. But first, let's see how to unwrap your data from Resource, or, using FP terms, fold it.

Let's use React for next example of folding your data into JSX. To do that we will use fold function, it provides a type-safe way to extract value/error from your resource and enforces you to handle all possible states.

import React from 'react'
import {fold} from '@throned/resource-ts'

type Movie = {id: string; title: string}

const renderMovies = fold(
  () => 'Nothing here',
  () => 'Loading movies...',
  (movies: Movie[]) => (
    <ul>
      {movies.map((movie) => (
        <li key={movie.id}>{movie.title}</li>
      ))}
    </ul>
  ),
  (error: Error) => `Oops! ${error.message}`,
)

const Movies = () => {
  const movies: Resource<Movie[], Error> = useMovies()

  return <div>{renderMovies(movies)}</div>
}

API

Nothing there yet

Guides

Usage with fp-ts

While you can use bare @throned/resource-ts, it is recommended to use it with fp-ts library, and especially with pipe function. Almost all function in @throned/resource-ts are curried and data usually comes last and that where pipe shines. It can infer type from previously provided value.

import {of, map, tap} from '@throned/resource-ts'
import {pipe} from 'fp-ts/lib/pipeable'

type TVSeries = {title: string, network: string}
const tvSeries = of({title: 'Peaky Blinders', network: 'BBC'})

// To use map without pipe and keep types you have to provide it explicitly
const showSeries = (series: TVSeries) => console.log({series})
const getNetwork = (series: TVSeries) => series.network
const network = map(getNetwork)(tap(showSeries)(tvSeries))

// Alternatively you can use it with pipe and types will be inferred for you
const network = pipe(
  tvSeries,
  tap(series => console.log({series}))
  map(series => series.network),
)

Working with multiple resources

Let's imagine next situation

import {of} from '@throned/resource-ts'

// You have two resources
const number = of(42)
const mulOptions = of({times: 10})

// And you have multiply function
const multiply = (x: number, {times}: {times: number}) => {
  return x * times
}

There are few ways of how you can call multiply function with values of these resources

chain

import {of, chain, map, tap} from '@throned/resource-fp'
import {pipe} from 'fp-ts/lib/pipeable'

const number = of(42)
const mulOptions = of({times: 10})

const multiply = (x: number, {times}: {times: number}) => {
  return x * times
}

pipe(
  number,
  chain((x) =>
    map((options: {times: number}) => multiply(x, options))(mulOptions),
  ),
  tap(console.log), // 420
)

ap

import {of, ap, map, tap} from '@throned/resource-fp'
import {pipe} from 'fp-ts/lib/pipeable'

const number = of(42)
const mulOptions = of({times: 10})

const multiply = (x: number) => ({times}: {times: number}) => {
  return x * times
}

/**
 * You can define useful function that uses ap and map
 * To apply a function to resources
 *
 * To see why this functions is not included in the lib check the next example
 */
const lift2 = <A, B, C, E>(
  a: Resource<A, E>,
  b: Resource<B, E>,
  f: (a: A) => (b: B) => C,
): Resource<C, E> => {
  return pipe(a, map(f), ap(b))
}

tap(console.log)(lift2(number, mulOptions, multiply)) // 420

combine

import {of, combine, map, tap} from '@throned/resource-fp'
import {pipe} from 'fp-ts/lib/pipeable'

const number = of(42)
const mulOptions = of({times: 10})

const multiply = (x: number, {times}: {times: number}) => {
  return x * times
}

pipe(
  /**
   * combine is the most convenient way to work with multiple resources
   * it merges all resources into one tuple that can be used later on
   */
  combine(number, mulOptions),
  map(([number, options]) => multiply(number, options))
  tap(console.log) // 420
)

// Also you can pass more than 2 resources into combine
combine(number, mulOptions) // Resource<[number, {times: number}], unknown>
combine(number, mulOptions, of('check me')) // Resource<[number, {times: number}, string], unknown>