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
279K
increased by0.02%
Maintainers
1
Created
Weekly downloads
 

Changelog

Source

0.4.0

  • Breaking Change
    • upgrade to fp-ts 0.5 (@gcanti)
    • currying of all APIs (@gcanti)

Readme

Source

A (partial) porting of scala monocle library to TypeScript

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.

Keywords

FAQs

Last updated on 23 Aug 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