Introduction
@fuiste/optics is a small TypeScript library for focusing on immutable data without turning every update into bespoke object-spread origami.
It gives you six optic kinds:
Total focus on required data.
Partial focus on optional data or union branches.
Total invertible mapping between two types.
Zero-or-more focus, usually arrays.
Read-only total focus.
Read-only zero-or-more extraction.
All optics compose through the standalone compose function. The result type is inferred from the optic kinds involved, so Lens plus Prism becomes Prism, anything read-only stays read-only, and traversals do what traversals do: politely eat the structure.
import { Lens, compose, each } from '@fuiste/optics'
type Team = { members: Array<{ name: string }> }
const members = Lens<Team>().prop('members')
const eachMember = each<{ name: string }>()
const name = Lens<{ name: string }>().prop('name')
const memberNames = compose(compose(members, eachMember), name)
memberNames.getAll({ members: [{ name: 'Ada' }, { name: 'Grace' }] })
// ['Ada', 'Grace']
Lawful by construction: the provided factories and combinators preserve the usual optic laws. Custom optics are still your responsibility, because TypeScript cannot save us from absolutely everything.
What This Library Optimizes For
- Immutable updates with stable, focused APIs.
- Type inference that survives composition.
- Small functional building blocks instead of class hierarchies.
- Ergonomic construction for common paths, records, arrays, and discriminated unions.
Install
pnpm add @fuiste/optics
Use npm, yarn, or bun if that is your particular local weather system.