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

performative-ts

v2.0.0

Published

Algebraic effects inspired, composable, minimalist and typed injection library

Downloads

105

Readme

Performative-ts

Composable, minimalist algebraic effects inspired, side-effect management library

npm install --save performative-ts
yarn add performative-ts

Use cases

👉 Providing a theme:

import { perform, withHandler } from 'performative-ts'

const getThemeEff = 'getThemeEff'

function Button({ label }) {
  const theme = perform(getThemeEff)

  return `
    <button style="color: ${theme.primaryColor}">
      ${label}
    </button>
  `
}

function App() {
  return Button({ label: 'Hello' })
}

console.log(
  withHandler(
    {
      [getThemeEff]() {
        return { primaryColor: 'paleblue' }
      },
    },
    () => App(),
  ),
)

👉 Add a logger:

import { perform, withHandler } from 'performative-ts'

// --- library

const logEff = 'logEff'

function log(info) {
  perform(logEff, info)
}

function withLogger(logFunction, wrappedFunc) {
  return withHandler({ [logEff]: logFunction }, wrappedFunc)
}

// --- userland

function Button({ label }) {
  log('rendering Button')

  return `
    <button style="color: ${theme.primaryColor}">
      ${label}
    </button>
  `
}

function App() {
  log('rendering App')

  return withLogger(
    (info) => log(`[App]: ${info}`),
    () => Button({ label: 'Hello' }),
  )
}

withLogger((info) => console.log(info), App)
// rendering Button
// [App]: rendering App

See examples for more

Best practices

👉 Rename your functions to add meaning:

import { perform, withHandler } from 'performative-ts'

const getThemeEff = 'getThemeEff'

export function useTheme() {
  return perform(getThemeEff)
}

export function provideTheme(theme, Component) {
  return withHandler({ [getThemeEff]: () => theme }, Component)
}

👉 Use a symbol to prevent collisions

const getThemeEff = Symbol('getThemeEff')

👉 Compose your handlers

import { compose } from 'your-favorite-lib'
import { bindHandler, perform } from 'performative-ts'

function sayName(name) {
  console.log(`Hello ${name || perform('getName')}`)
}

const composed = compose(
  bindHandler(['getName', () => 'John Snow']),
  bindHandler(['getName', () => perform('getName').toUpperCase()]),
)(sayName)

composed('Arya') // Hello Arya
composed() // Hello JOHN SNOW

👉 Capture current frame for later execution

import { captureFrame, bindFrame, withFrame } from 'performative-ts/frame'

const frame = captureFrame()

// later
const boundListener = bindFrame(frame, listener)
button.addEventListener('click', boundListener)

setTimeout(() => {
  withFrame(frame, () => computation())
}, 1000)

👉 Use with typescript

import { perform, withHandler } from 'performative-ts'
import type { EffectName } from 'performative-ts'

export type Theme = {
  primaryColor: string
}

const getThemeEff: EffectName<() => Theme> = Symbol('getThemeEff')

export function useTheme(): Theme {
  return perform(getThemeEff)
}

export function provideTheme<C extends Function>(theme: Theme, Component: C): C {
  // for better typings with typescript, the library allow to provide handlers as tuples
  return withHandler([getThemeEff, () => theme], Component)
}

API reference

perform

perform(effectName, ...args): effectResult or throws

Performs a effect and return its result. Throws if the corresponding effect handler is not declared during its execution.

performAndFailSilently(effectName, ...args): effectResult | undefined

Performs a effect safely and return its result. Returns undefined if the corresponding effect handler is not declared during its execution.

withHandler

withHandler(handler, computation): computationResult

Calls a computation (a function taking no arguments) with the provided effect handler.

withHandler(...handlerTuples, computation): computationResult

Calls a computation (a function taking no arguments) with the provided effect handler functions.

bindHandler

bindHandler(handler, func): func

Binds an effect handler to the provided function.

bindHandler(...handlerTuples, func): func

Binds effect handler functions to the provided function.

curried bindHandler

bindHandler(handler): func => func

Returns a function that will bind the given effect handler to another function.

bindHandler(...handlerTuples): func => func

Returns a function that will bind the given effect handler functions to another function.

frames

captureFrame(): currentFrame

Captures current execution frame

withFrame(frame, computation): computationResult

Calls a computation (a function taking no arguments) with the provided execution frame.

bindFrame(frame, func): func

Binds an execution frame to the provided function.

Types

EffectName

An unique effect identifier. Can be a string, number or symbol.

Handler

An object consisting of EffectNames as keys and EffectHandlerFunctions as values.

HandlerTuple

A tuple consisting of EffectName as first element and EffectHandlerFunction as second element.

Frame

An object keeping the reference to its own effect handlers and to its parent frame.