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

zoptic

v0.1.6

Published

Simple optics library for Typescript

Downloads

17

Readme

zoptic

Simple optics library for Typescript

Example


import * as Z from 'zoptic'

interface Address {
  street: string;
  apartment?: string;
  zip: number;
}

interface Person {
  name: string;
  age: number;
  address: Address;
}

const person: Person = {
  name: "John",
  age: 30,
  address: {
    street: "Test street",
    apartment: "A310",
    zip: "52900",
  },
};

// Create an optic that focuses on the street of persons address

const o1 = Z.chain<Person>().prop("address").prop("street");

// Read the street using the optics

Z.get(o1, person);

// Update the street using the optics

Z.set(o1, person, "Test street 2");

// Or you can use the update method

Z.update(o1, (s) => s + " suffix")(person);

// Create an optional optics for `apartment`

const o2 = Z.chain<Person>().prop("address").prop("apartment").opt();

Three kinds of optics

This library defines three kinds of optics:

  • Optic with one focus (Optic<"One", ...>)
  • Optic with optional focus (Optic<"Optional", ...>)
  • Optic with zero to many focus values (Optic<"Traversal", ...>)

When you compose two optics together (with compose), the resulting optic type is the more general of those two. For example if you compose One optic with Optional one, the resulting object is Optional.

Reading focus values from data

There are three functions to read data using optics: get, preview and collect.

  • get is used for optics that always have one focus.
  • preview is used for optics that have optional focus.
  • collect is used for optics that can have zero to many focus values.

Chain

The easiest way to use the optics is through the Chain-type. You create value of Chain using the Z.chain()-function.

Chain provides following functions:

prop

Creates an optic that focuses on a certain property of an object.

filter

Creates a Traversal optic that focuses all elements of an array that matches a predicate. The current focus must be an array value.

collect

Converts an optic which focus is an array to a Traversal optic. The current focus must be an array value.

at

Focuses into one element of an array (specified by an index). The current focus must be an array value. The resulting optic is Optional.

opt

Converts optic that may have undefined focus to an Optional optic.

guard

Restricts a type of focus. This may be used for example to restrict a tagged union type.

compose

Helper function to compose current optics with another one.

Functions for creating different optics manually

If the Chain doesn't have a method to create an optic that you need, you can create an optic manually with following functions and then use .compose on the Chain to compose that optic with the current one.

adapter

const adapterOptic = <S, A>(
  get: (s: S) => A,
  set: (a: A) => S
): Optic<"One", S, A>

Creates an optic that adapts the whole value to the focus value, and viceversa.

lensOptic

const lensOptic = <S, A>(
  get: (s: S) => A,
  set: (a: A, s: S) => S
): Optic<"One", S, A>

Lens access a certain focus value from a bigger context.

To build the bigger context Lens needs the new focus value and the old context.

prismOptic

const prismOptic = <S, A>(
  get: (s: S) => A | undefined,
  set: (a: A) => S
): Optic<"Optional", S, A>

Prism is similar then Lens that it access a certain focus from a bigger context. Prism have the possibility that the focus value isn't available.

With prism you can build the bigger context using only the focus value.

affineOptic

const affineOptic = <S, A>(
  get: (s: S) => A | undefined,
  set: (a: A, s: S) => S
): Optic<"Optional", S, A>

Affine may or may not have the focus value.

With affine you must provide the focus and the old context to build the new context.

traversalOptic

compose

Composes two optics together.

const PersonAddress = Z.chain<Person>().prop("address");
const AddressStreet = Z.chain<Address>().prop("street");
const O = Z.compose(PersonAddress, AddressStreet);