monocle-ts

repository·master·Indexed 22 days ago

https://github.com/gcanti/monocle-ts

A TypeScript port of the Scala Monocle library providing functional optics for immutable data manipulation. It includes Lenses for mandatory fields, Optionals for potentially missing fields, Prisms, Traversals, and Isos for bidirectional transformations. The library also features a Fold class for aggregating targets, a Getter for read-only views, and an experimental At module for accessing elements within Maps, Records, and Sets.

Tokens
29.9K
Snippets
110
Records
137
Agent score
74%

What's inside monocle-ts

  1. What is a Lens and how does it work?

    master

    A Lens is an optic used to zoom into a product. It allows you to focus on a specific part of a larger structure. A Lens<S, A> represents a focus on an element of type A within a product of type S.

    To be a valid Lens, it must satisfy these three laws:

    1. get(set(a)(s)) = a (Getting after setting returns the value you set)
    2. set(get(s))(s) = s (Setting the current value back into the product returns the original product)
    3. set(a)(set(a)(s)) = set(a)(s) (Setting the same value twice is the same as setting it once)

    Note: This module is experimental and subject to change.

    // Conceptual interface of a Lens
    export interface Lens<S, A> {
      readonly get: (s: S) => A
      readonly set: (a: A) => (s: S) => S
    }
  2. What is a Traversal?

    master

    A Traversal is a generalization of an Optional. While an Optional focuses on zero or one target, a Traversal allows you to focus from a source type S into zero to n values of type A.

    Common use cases include focusing on all elements within a container like a ReadonlyArray or an Option. This is achieved through the relationship between the Traversable typeclass and Traversal.

    Note: This module is experimental and subject to change without notice.

  3. What is an Iso?

    master

    An Iso (Isomorphism) is an optic that converts elements of type S into elements of type A without loss of information. It provides a lossless, two-way mapping between two types.

    To be a valid Iso, it must satisfy two laws:

    1. reverseGet(get(s)) = s
    2. get(reversetGet(a)) = a

    Note: This module is currently experimental and subject to change without notice.

  4. What is a Prism?

    master

    A Prism is an experimental optic used to select part of a sum type (an algebraic data type). It allows you to focus on a specific variant of a type, providing a way to attempt to extract a value (getOption) or reconstruct the original structure from a value (reverseGet).

    Note: This module is experimental and subject to change without notice.

    Laws:

    1. pipe(getOption(s), fold(() => s, reverseGet)) = s
    2. getOption(reverseGet(a)) = some(a)
  5. What is an Optional in monocle-ts?

    master

    An Optional<S, A> is an optic used to zoom into a product where the target element might not exist. It is defined by two type parameters: S (the source product) and A (the optional element inside S).

    Unlike a Lens, which assumes the target always exists, an Optional handles cases where the focus is missing.

    Note: This module is experimental and subject to change without notice.

    // Conceptual interface structure
    export interface Optional<S, A> {
      readonly getOption: (s: S) => Option<A>
      readonly set: (a: A) => (s: S) => S
    }
  6. What is the At module?

    master

    The At module is an experimental feature (added in v2.3.0) that provides a way to create lenses for accessing elements within structures like Maps, Records, and Sets. It provides a high-level way to focus on a specific key or element within a collection using a single interface.

    Warning: This module is experimental. Features are in a high state of flux and may change without notice.

  7. How Lenses and Optionals work together

    master

    A Lens requires the target field to be mandatory. If you need to zoom into a field that might not exist (e.g., the first character of a string, which is absent if the string is empty), you must use an Optional.

    Key Concepts:

    • Lens: Used for mandatory fields. Composing two Lenses results in a Lens.
    • Optional: A "partial Lens" used for fields that might be missing. Composing two Optionals results in an Optional.
    • Interoperability: You can convert a Lens into an Optional using .asOptional(). Composing an Optional with a Lens always produces an Optional.

    This allows you to navigate through mandatory structures and then safely transition into optional paths.

    import { Optional } from 'monocle-ts'
    import { some, none } from 'fp-ts/lib/Option'
    
    // Define an Optional for the first letter of a string
    const firstLetter = new Optional<string, string>(
      s => (s.length > 0 ? some(s[0]) : none), 
      a => s => a + s.substring(1)
    )
    
    // Navigate via Lens, convert to Optional, then compose with the Optional lens
    company
      .compose(address)
      .compose(street)
      .compose(name)
      .asOptional()
      .compose(firstLetter)
      .modify(s => s.toUpperCase())(employee)
  8. Use Either.ts for error handling and branching logic

    master
    The Either module provides a way to represent a value that can be one of two types: a Left (typically representing an error or failure) or a Right (typically representing success or a valid value). It is used to handle branching logic in a functional manner, ensuring that both success and failure paths are explicitly accounted for.
  9. How Lenses work for immutable nested object updates

    master

    A Lens is an abstraction used to focus on a specific part of a data structure to view or modify it immutably. Instead of manually spreading nested objects (e.g., {...obj, a: {...obj.a, b: ...}}), you can compose Lenses to create a path to a deeply nested property.

    Key operations:

    • Lens.fromProp<A>()('key'): Creates a Lens from a property of type A.
    • compose: Combines two Lenses (e.g., a Lens from A to B and B to C creates a Lens from A to C).
    • modify: Applies a function to the focused value and returns a new version of the original structure.
    • fromPath: A convenience method to create a Lens using an array of property names.
    import { Lens } from 'monocle-ts'
    
    // Creating individual lenses
    const company = Lens.fromProp<Employee>()('company')
    const address = Lens.fromProp<Company>()('address')
    
    // Composing them to reach a deep property
    const name = company.compose(address).compose(street).compose(name)
    
    // Modifying the value
    const capitalizeName = name.modify(capitalize)
    const newEmployee = capitalizeName(employee)
    
    // Or using fromPath for less boilerplate
    const namePath = Lens.fromPath<Employee>()(['company', 'address', 'street', 'name'])
    const newEmployeePath = namePath.modify(capitalize)(employee)
  10. Compose Lenses and Isos

    master

    Optics in monocle-ts can be composed to drill deeper into data structures.

    • Iso Composition: Iso.compose(ab: Iso<A, B>) creates a new Iso<S, B>.
    • Lens Composition: Lens.compose(ab: Lens<A, B>) creates a new Lens<S, B>.
    • Mixed Composition:
      • Lens.composeIso(ab: Iso<A, B>) results in a Lens<S, B>.
      • Lens.composePrism(ab: Prism<A, B>) results in an Optional<S, B>.
      • Lens.composeOptional(ab: Optional<A, B>) results in an Optional<S, B>.
  11. TypeScript compatibility and requirements

    master

    Monocle-ts is compatible with TypeScript 2.8.0 and above. It is tested against TypeScript 3.2.2.

    Important: If you are using a version of TypeScript older than 3.0.1, you must polyfill the unknown type. It is recommended to use unknown-ts for this purpose.