Skip to content

anthonyjoeseph/spectacles-ts

Folders and files

NameName
Last commit message
Last commit date
Apr 7, 2022
Mar 26, 2022
Mar 25, 2022
Apr 7, 2022
Apr 5, 2022
Mar 25, 2022
Aug 1, 2021
Mar 25, 2022
Aug 1, 2021
Mar 30, 2022
Mar 25, 2022
Apr 5, 2022
Apr 29, 2022
Apr 6, 2022
Mar 25, 2022
Apr 7, 2022
Apr 5, 2022
Mar 29, 2022
Mar 29, 2022
Mar 25, 2022
Apr 5, 2022

Repository files navigation

spectacles-ts 👓

Practical Optics • Unfancy monocle-ts 🧐

A facade on top of monocle-ts

Blog post

Try it out!

prop video

Installation

yarn add fp-ts spectacles-ts

Examples

get

monocle-ts equivalent

import { pipe } from 'fp-ts/function'
import * as O from 'fp-ts/Option'
import { get } from 'spectacles-ts'

const gotten = pipe(
  { a: { b: ['abc', 'def'] } },
  get('a.b.[number]', 0)
)
// gotten: O.Option<string>

set

monocle-ts equivalent

immutability-helper equivalent

import { pipe } from 'fp-ts/function'
import { set } from 'spectacles-ts'

const beenSet = pipe(
  { a: ['abc', 'def'] },
  set('a.[number]', 1, 'xyz')
)
// beenSet: { a: string[] }

setOption

monocle-ts equivalent

import { pipe } from 'fp-ts/function'
import { setOption } from 'spectacles-ts'

const setOptioned = pipe(
  { a: ['abc', 'def'] },
  setOption('a.[number]', 1, 'xyz')
)
// setOptioned: O.Option<{ a: string[] }>

upsert

immutability-helper equivalents

import { pipe } from 'fp-ts/function'
import { upsert } from 'spectacles-ts'

const upserted = pipe(
  { a: { b: 123 } },
  upsert('a', 'c', 'abc')
)
// upserted: { a: { b: number; readonly c: string } }

remove

import { pipe } from 'fp-ts/function'
import { remove } from 'spectacles-ts'

const removed = pipe(
  { a: { b: 123, c: false } },
  remove('a.c')
)
// removed: { a: { b: number } }

rename

import { pipe } from 'fp-ts/function'
import type { NonEmptyArray } from 'fp-ts/NonEmptyArray'
import type { Option } from 'fp-ts/Option'
import { rename } from 'spectacles-ts'

const renamed = pipe(
  { a: { b: 123, c: 'abc' } },
  rename('a.c', 'd')
)
// renamed: { a: { b: number; readonly d: string } }

modify

monocle-ts equivalent

immutability-helper equivalent

import { pipe } from 'fp-ts/function'
import { modify } from 'spectacles-ts'

const modified = pipe(
  { a: [{ b: 123 }] },
  modify('a.[number].b', 0, (j) => j + 4)
)
// modified: { a: { b: number }[] }

modifyOption

monocle-ts equivalent

import { pipe } from 'fp-ts/function'
import * as O from 'fp-ts/Option'
import { modifyOption } from 'spectacles-ts'

const modifyOptioned = pipe(
  { a: [{ b: 123 }] },
  modifyOption('a.[number].b', 0, (j) => j + 4)
)
// modifyOptioned: O.Option<{ a: { b: number }[] }>

modifyW

import { pipe } from 'fp-ts/function'
import { modifyW } from 'spectacles-ts'

const modifyWidened = pipe(
  { a: 123 } as { a: number | undefined },
  modifyW('a?', (j) => `${j + 2}`)
)
// modifyWidened: { a: string | undefined }

modifyOptionW

import { pipe } from 'fp-ts/function'
import * as O from 'fp-ts/Option'
import { modifyOptionW } from 'spectacles-ts'

const modifyOptionWidened = pipe(
  { a: 123 } as { a: number | undefined },
  modifyOptionW('a?', (j) => `${j + 2}`)
)
// modifyOptionWidened: O.Option<{ a: string | undefined }>

modifyF

monocle-ts equivalent

import { pipe } from 'fp-ts/function'
import * as E from 'fp-ts/Either'
import { modifyF } from 'spectacles-ts'

const modifieFunctored = pipe(
  { a: { b: 123 } },
  modifyF(E.Applicative)(
    'a.b',
    (j) => j > 10 ? E.left<string, never>('fail') : E.right(j - 10)
  )
)
// modifieFunctored: E.Either<string, { a: { b: number } }>

Operations

usage       equals Optional monocle
get('a')(x) 1 no prop
get('c.[0]')(x) 123 no component
get('d.[number]', 0)(x) O.some({ e: 123 }) yes index
get('f.[string]', 'a')(x) O.some([123]) yes key
get('g?')(x) O.some(2) yes fromNullable
get('h.?some')(x) O.some(2) yes some
get('i.?left')(x) O.none yes left
get('i.?right')(x) O.some(2) yes right
get('j.shape:circle.radius')(x) O.some(100) yes filter
get('d.[]>.e')(x) [123, 456] never traverse
Array
get('f.{}>.e')(x) [123, 456] never traverse
Record
(keys sorted alpha-
betically)
import * as O from 'fp-ts/Option'
import * as E from 'fp-ts/Either'
interface Data {
  a: number
  b: number
  c: [number, string]
  d: { e: number }[]
  f: Record<string, number[]>
  g?: number
  h: O.Option<number>
  i: E.Either<string, number>
  j: { shape: "circle"; radius: number } | { shape: "rectangle"; width: number; height: number }
}
const x: Data = {
  a: 1,
  b: 2,
  c: [123, 'abc'],
  d: [{ e: 123 }, { e: 456 }],
  f: { b: { e: 456 }, a: { e: 123 } },
  g: 2,
  h: O.some(2),
  i: E.right(2),
  j: { shape: "circle", radius: 100 }
}

Restrictions

For the time being, "strictNullChecks" must be set to false for spectacles to behave properly (see this issue)

Social Media

Follow me on twitter! @typesafeFE

About

Practical Optics • Unfancy monocle-ts

Resources

Stars

Watchers

Forks

Packages

No packages published