Socket
Socket
Sign inDemoInstall

monocle-ts

Package Overview
Dependencies
1
Maintainers
1
Versions
55
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    monocle-ts

A porting of scala monocle library to TypeScript


Version published
Weekly downloads
309K
increased by15.91%
Maintainers
1
Install size
636 kB
Created
Weekly downloads
 

Changelog

Source

0.5.1

  • Experimental
    • add Flowtype support (@gcanti)

Readme

Source

Motivation

(Adapted from monocle site)

Modifying immutable nested object in JavaScript is verbose which makes code difficult to understand and reason about.

Let's have a look at some examples:

interface Street { num: number, name: string }
interface Address { city: string, street: Street }
interface Company { name: string, address: Address }
interface Employee { name: string, company: Company }

Let’s say we have an employee and we need to upper case the first character of his company street name. Here is how we could write it in vanilla JavaScript

const employee: Employee = {
  name: "john",
  company: {
    name: "awesome inc",
    address: {
      city: "london",
      street: {
        num: 23,
        name: "high street"
      }
    }
  }
}

const capitalize = (s: string): string => s.substring(0, 1).toUpperCase() + s.substring(1)

const employee2 = {
  ...employee,
  company: {
    ...employee.company,
    address: {
      ...employee.company.address,
      street: {
        ...employee.company.address.street,
        name: capitalize(employee.company.address.street.name)
      }
    }
  }
}

As we can see copy is not convenient to update nested objects because we need to repeat ourselves. Let's see what could we do with monocle-ts

import { Lens, Optional } from 'monocle-ts'

const company = Lens.fromProp<Employee, 'company'>('company')
const address = Lens.fromProp<Company, 'address'>('address')
const street = Lens.fromProp<Address, 'street'>('street')
const name = Lens.fromProp<Street, 'name'>('name')

company.compose(address).compose(street).compose(name)

compose takes two Lenses, one from A to B and another one from B to C and creates a third Lens from A to C. Therefore, after composing company, address, street and name, we obtain a Lens from Employee to string (the street name). Now we can use this Lens issued from the composition to modify the street name using the function capitalize

company
  .compose(address)
  .compose(street)
  .compose(name)
  .modify(capitalize)(employee)

Here modify lift a function string => string to a function Employee => Employee. It works but it would be clearer if we could zoom into the first character of a string with a Lens. However, we cannot write such a Lens because Lenses require the field they are directed at to be mandatory. In our case the first character of a string is optional as a string can be empty. So we need another abstraction that would be a sort of partial Lens, in monocle-ts it is called an Optional.

import { some, none } from 'fp-ts/lib/Option'

const firstLetter = new Optional<string, string>(
  s => s.length > 0 ? some(s[0]) : none,
  a => s => a + s.substring(1)
)

company
  .compose(address)
  .compose(street)
  .compose(name)
  .asOptional()
  .compose(firstLetter)
  .modify(s => s.toUpperCase())(employee)

Similarly to compose for lenses, compose for optionals takes two Optionals, one from A to B and another from B to C and creates a third Optional from A to C. All Lenses can be seen as Optionals where the optional element to zoom into is always present, hence composing an Optional and a Lens always produces an Optional.

Table of Contents generated with DocToc

Iso

class Iso<S, A> {
  constructor(readonly get: (s: S) => A, readonly reverseGet: (a: A) => S)
}

Methods

unwrap

(s: S) => A

Alias of get

to

(s: S) => A

Alias of get

wrap

(a: A) => S

Alias of reverseGet

from

(a: A) => S

Alias of reverseGet

modify

(f: (a: A) => A): (s: S) => S

asLens

(): Lens<S, A>

view an Iso as a Lens

asPrism

(): Prism<S, A>

view an Iso as a Prism

asOptional

(): Optional<S, A>

view an Iso as a Optional

asTraversal

(): Traversal<S, A>

view an Iso as a Traversal

asFold

(): Fold<S, A>

view an Iso as a Fold

asGetter

(): Getter<S, A>

view an Iso as a Getter

asSetter

(): Setter<S, A>

view an Iso as a Setter

compose

<B>(ab: Iso<A, B>): Iso<S, B>

compose an Iso with an Iso

composeLens

<B>(ab: Lens<A, B>): Lens<S, B>

compose an Iso with a Lens

composePrism

<B>(ab: Prism<A, B>): Prism<S, B>

compose an Iso with a Prism

composeOptional

<B>(ab: Optional<A, B>): Optional<S, B>

compose an Iso with an Optional

composeTraversal

<B>(ab: Traversal<A, B>): Traversal<S, B>

compose an Iso with a Traversal

composeFold

<B>(ab: Fold<A, B>): Fold<S, B>

compose an Iso with a Fold

composeGetter

<B>(ab: Getter<A, B>): Getter<S, B>

compose an Iso with a Getter

composeSetter

<B>(ab: Setter<A, B>): Setter<S, B>

compose an Iso with a Setter

Lens

class Lens<S, A> {
  constructor(readonly get: (s: S) => A, readonly set: (a: A) => (s: S) => S)
}

fromPath

// other 9 overloadings
<T, K1 extends keyof T>(path: [K1]): Lens<T, T[K1]>

Example

type Person = {
  name: string
  age: number
  address: {
    city: string
  }
}

const city = Lens.fromPath<Person, 'address', 'city'>(['address', 'city'])

const person: Person = { name: 'Giulio', age: 43, address: { city: 'Milan' } }

console.log(city.get(person)) // Milan
console.log(city.set('London')(person)) // { name: 'Giulio', age: 43, address: { city: 'London' } }

fromProp

<T, P extends keyof T>(prop: P): Lens<T, T[P]>

generate a lens from a type and a prop

Example

type Person = {
  name: string
  age: number
}

const age = Lens.fromProp<Person, 'age'>('age')

const person: Person = { name: 'Giulio', age: 43 }

console.log(age.get(person)) // 43
console.log(age.set(44)(person)) // { name: 'Giulio', age: 44 }

fromNullableProp

<S, A extends S[K], K extends keyof S>(k: K, defaultValue: A): Lens<S, A>

generate a lens from a type and a prop whose type is nullable

Example

interface Outer {
  inner?: Inner
}

interface Inner {
  value: number
  foo: string
}

const inner = Lens.fromNullableProp<Outer, Inner, 'inner'>('inner', { value: 0, foo: 'foo' })
const value = Lens.fromProp<Inner, 'value'>('value')
const lens = inner.compose(value)

console.log(lens.set(1)({})) // { inner: { value: 1, foo: 'foo' } }
console.log(lens.get({})) // 0
console.log(lens.set(1)({ inner: { value: 1, foo: 'bar' } })) // { inner: { value: 1, foo: 'bar' } }
console.log(lens.get({ inner: { value: 1, foo: 'bar' } })) // 1

Methods

modify

(f: (a: A) => A): (s: S) => S

asOptional

(): Optional<S, A>

view a Lens as a Optional

asTraversal

(): Traversal<S, A>

view a Lens as a Traversal

asSetter

(): Setter<S, A>

view a Lens as a Setter

asGetter

(): Getter<S, A>

view a Lens as a Getter

asFold

(): Fold<S, A>

view a Lens as a Fold

compose

<B>(ab: Lens<A, B>): Lens<S, B>

compose a Lens with a Lens

composeGetter

<B>(ab: Getter<A, B>): Getter<S, B>

compose a Lens with a Getter

composeFold

<B>(ab: Fold<A, B>): Fold<S, B>

compose a Lens with a Fold

composeOptional

<B>(ab: Optional<A, B>): Optional<S, B>

compose a Lens with an Optional

composeTraversal

<B>(ab: Traversal<A, B>): Traversal<S, B>

compose a Lens with an Traversal

composeSetter

<B>(ab: Setter<A, B>): Setter<S, B>

compose a Lens with an Setter

composeIso

<B>(ab: Iso<A, B>): Lens<S, B>

compose a Lens with an Iso

composePrism

<B>(ab: Prism<A, B>): Optional<S, B>

compose a Lens with a Prism

Prism

class Prism<S, A> {
  constructor(readonly getOption: (s: S) => Option<A>, readonly reverseGet: (a: A) => S)
}

fromPredicate

<A>(predicate: Predicate<A>): Prism<A, A>

some

<A>(): Prism<Option<A>, A>

Methods

modify

(f: (a: A) => A): (s: S) => S

modifyOption

(f: (a: A) => A): (s: S) => Option<S>

set

(a: A): (s: S) => S

set the target of a Prism with a value

asOptional

(): Optional<S, A>

view a Prism as a Optional

asTraversal

(): Traversal<S, A>

view a Prism as a Traversal

asSetter

(): Setter<S, A>

view a Prism as a Setter

asFold

(): Fold<S, A>

view a Prism as a Fold

compose

<B>(ab: Prism<A, B>): Prism<S, B>

compose a Prism with a Prism

composeOptional

<B>(ab: Optional<A, B>): Optional<S, B>

compose a Prism with a Optional

composeTraversal

<B>(ab: Traversal<A, B>): Traversal<S, B>

compose a Prism with a Traversal

composeFold

<B>(ab: Fold<A, B>): Fold<S, B>

compose a Prism with a Fold

composeSetter

<B>(ab: Setter<A, B>): Setter<S, B>

compose a Prism with a Setter

composeIso

<B>(ab: Iso<A, B>): Prism<S, B>

compose a Prism with a Iso

composeLens

<B>(ab: Lens<A, B>): Optional<S, B>

compose a Prism with a Lens

composeGetter

<B>(ab: Getter<A, B>): Fold<S, B>

compose a Prism with a Getter

Optional

class Optional<S, A> {
  constructor(readonly getOption: (s: S) => Option<A>, readonly set: (a: A) => (s: S) => S) {}
}

fromNullableProp

<S, A extends S[K], K extends keyof S>(k: K): Optional<S, A>

Example

interface Phone {
  number: string
}
interface Employment {
  phone?: Phone
}
interface Info {
  employment?: Employment
}
interface Response {
  info?: Info
}

const info = Optional.fromNullableProp<Response, Info, 'info'>('info')
const employment = Optional.fromNullableProp<Info, Employment, 'employment'>('employment')
const phone = Optional.fromNullableProp<Employment, Phone, 'phone'>('phone')
const number = Lens.fromProp<Phone, 'number'>('number')
const numberFromResponse = info
  .compose(employment)
  .compose(phone)
  .composeLens(number)

const response1: Response = {
  info: {
    employment: {
      phone: {
        number: '555-1234'
      }
    }
  }
}
const response2: Response = {
  info: {
    employment: {}
  }
}

numberFromResponse.getOption(response1) // some('555-1234')
numberFromResponse.getOption(response2) // none

Methods

modify

(f: (a: A) => A): (s: S) => S

modifyOption

(f: (a: A) => A): (s: S) => Option<S>

asTraversal

(): Traversal<S, A>

view a Optional as a Traversal

asFold

(): Fold<S, A>

view an Optional as a Fold

asSetter

(): Setter<S, A>

view an Optional as a Setter

compose

<B>(ab: Optional<A, B>): Optional<S, B>

compose a Optional with a Optional

composeTraversal

<B>(ab: Traversal<A, B>): Traversal<S, B>

compose an Optional with a Traversal

composeFold

<B>(ab: Fold<A, B>): Fold<S, B>

compose an Optional with a Fold

composeSetter

<B>(ab: Setter<A, B>): Setter<S, B>

compose an Optional with a Setter

composeLens

<B>(ab: Lens<A, B>): Optional<S, B>

compose an Optional with a Lens

composePrism

<B>(ab: Prism<A, B>): Optional<S, B>

compose an Optional with a Prism

composeIso

<B>(ab: Iso<A, B>): Optional<S, B>

compose an Optional with a Iso

composeGetter

<B>(ab: Getter<A, B>): Fold<S, B>

compose an Optional with a Getter

Traversal

class Traversal<S, A> {
  constructor(
    readonly modifyF: <F>(F: Applicative<F>) => (f: (a: A) => HKT<F, A>) => (s: S) => HKT<F, S>
  )
}

Methods

modify

(f: (a: A) => A): (s: S) => S

set

(a: A): (s: S) => S

asFold

(): Fold<S, A>

view a Traversal as a Fold

asSetter

(): Setter<S, A>

view a Traversal as a Setter

compose

<B>(ab: Traversal<A, B>): Traversal<S, B>

compose a Traversal with a Traversal

composeFold

<B>(ab: Fold<A, B>): Fold<S, B>

compose a Traversal with a Fold

composeSetter

<B>(ab: Setter<A, B>): Setter<S, B>

compose a Traversal with a Setter

composeOptional

<B>(ab: Optional<A, B>): Traversal<S, B>

compose a Traversal with a Optional

composeLens

<B>(ab: Lens<A, B>): Traversal<S, B>

compose a Traversal with a Lens

composePrism

<B>(ab: Prism<A, B>): Traversal<S, B>

compose a Traversal with a Prism

composeIso

<B>(ab: Iso<A, B>): Traversal<S, B>

compose a Traversal with a Iso

composeGetter

<B>(ab: Getter<A, B>): Fold<S, B>

compose a Traversal with a Getter

Getter

class Getter<S, A> {
  constructor(readonly get: (s: S) => A)
}

Methods

asFold

(): Fold<S, A>

view a Getter as a Fold

compose

<B>(ab: Getter<A, B>): Getter<S, B>

compose a Getter with a Getter

composeFold

<B>(ab: Fold<A, B>): Fold<S, B>

compose a Getter with a Fold

composeLens

<B>(ab: Lens<A, B>): Getter<S, B>

compose a Getter with a Lens

composeIso

<B>(ab: Iso<A, B>): Getter<S, B>

compose a Getter with a Iso

composeTraversal

<B>(ab: Traversal<A, B>): Fold<S, B>

compose a Getter with a Optional

composeOptional

<B>(ab: Optional<A, B>): Fold<S, B>

compose a Getter with a Optional

composePrism

<B>(ab: Prism<A, B>): Fold<S, B>

compose a Getter with a Prism

Fold

class Fold<S, A> {
  constructor(readonly foldMap: <M>(M: Monoid<M>) => (f: (a: A) => M) => (s: S) => M)
}

Methods

compose

<B>(ab: Fold<A, B>): Fold<S, B>

compose a Fold with a Fold

composeGetter

<B>(ab: Getter<A, B>): Fold<S, B>

compose a Fold with a Getter

composeTraversal

<B>(ab: Traversal<A, B>): Fold<S, B>

compose a Fold with a Traversal

composeOptional

<B>(ab: Optional<A, B>): Fold<S, B>

compose a Fold with a Optional

composeLens

<B>(ab: Lens<A, B>): Fold<S, B>

compose a Fold with a Lens

composePrism

<B>(ab: Prism<A, B>): Fold<S, B>

compose a Fold with a Prism

composeIso

<B>(ab: Iso<A, B>): Fold<S, B>

compose a Fold with a Iso

find

(p: Predicate<A>): (s: S) => Option<A>

find the first target of a Fold matching the predicate

headOption

(s: S): Option<A>

get the first target of a Fold

getAll

(s: S): Array<A>

get all the targets of a Fold

exist

(p: Predicate<A>): Predicate<S>

check if at least one target satisfies the predicate

all

(p: Predicate<A>): Predicate<S>

check if all targets satisfy the predicate

Setter

class Setter<S, A> {
  constructor(readonly modify: (f: (a: A) => A) => (s: S) => S)
}

Methods

set

(a: A): (s: S) => S

compose

<B>(ab: Setter<A, B>): Setter<S, B>

compose a Setter with a Setter

composeTraversal

<B>(ab: Traversal<A, B>): Setter<S, B>

compose a Setter with a Traversal

composeOptional

<B>(ab: Optional<A, B>): Setter<S, B>

compose a Setter with a Optional

composeLens

<B>(ab: Lens<A, B>): Setter<S, B>

compose a Setter with a Lens

composePrism

<B>(ab: Prism<A, B>): Setter<S, B>

compose a Setter with a Prism

composeIso

<B>(ab: Iso<A, B>): Setter<S, B>

compose a Setter with a Iso

fromTraversable

<T>(T: Traversable<T>): <A>() => Traversal<HKT<T, A>, A>

create a Traversal from a Traversable

fromFoldable

<F>(F: Foldable<F>): <A>() => Fold<HKT<F, A>, A>

create a Fold from a Foldable

Keywords

FAQs

Last updated on 27 Nov 2017

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc