effect-optics

Implements composable type-safe optics for immutable access and updates to nested TypeScript data structures.

1|Updated Aug 24, 2026
One-click install
npx skills add https://github.com/lambdasolver2/opencode-effect-harness --skill effect-optics-lambdasolver2
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: effect-optics
Source: https://github.com/lambdasolver2/opencode-effect-harness/tree/main/packages/module-typescript/assets/skills/effect-optics
Command: npx skills add https://github.com/lambdasolver2/opencode-effect-harness --skill effect-optics-lambdasolver2

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill requires effect.

What problem does it solve? Deeply nested immutable updates in TypeScript require verbose, error-prone spread operations that duplicate navigation logic and lose type safety across tagged unions, optional fields, and collections. ## Core Features & Use Cases - Composable Optic Chains: Build Iso, Lens, Prism, Optional, and Traversal optics with chainable methods like .key(), .tag(), .at(), and .forEach() starting from Optic.id<S>(). - Safe Union and Collection Handling: Narrow tagged unions with .tag(), filter with .check() and .refine(), and traverse arrays with .modifyAll() while non-matching cases no-op safely. - Schema Integration: Generate optics directly from Schema definitions via Schema.toIso, including class-based schemas. - Use Case: Define _streetName = Optic.id<Employee>().key('company').key('address').key('street').key('name') once, then reuse it with .modify() for capitalize, uppercase, or any transform instead of repeating nested spreads. ## Quick Start Ask the AI to create an Effect Optic lens chain that immutably updates a deeply nested field in your TypeScript state type.

Frequently Asked Questions about effect-optics

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I update a deeply nested field immutably in TypeScript with Effect?▼

Define an optic once with Optic.id<S>().key('a').key('b') and call .replace(value, state) or .modify(fn) to produce an updated copy. This replaces repetitive nested spread syntax with a reusable, type-safe path.

What is the difference between Lens, Prism, Optional, and Traversal in Effect Optic?▼

A Lens focuses an always-present field, a Prism focuses a union variant that may not match, an Optional handles cases where both reading and writing can fail, and a Traversal operates over zero or more collection elements. Composing two optics yields the weaker kind.

How do I update a field inside a tagged union variant safely?▼

Use .tag('Variant') to narrow the union before chaining .key() into the variant's fields. Replace and modify become no-ops on non-matching variants, returning the original value unchanged.

Does Effect Optic work with class instances or only plain objects?▼

Optics work with plain JavaScript objects, structs, records, tuples, and arrays. Class instances cause runtime errors on replace or modify unless the optic is generated via Schema.toIso on a class schema.

Why does my optic replace silently return the original value?▼

The replace method returns the original S unchanged when the optic cannot focus, such as a missing key or non-matching tag. Use replaceResult or getResult to receive an explicit Result with failure details instead.

How do I update only certain elements of an array with Effect Optic?▼

Use .forEach() combined with .check() or .notUndefined() to filter focused elements, then apply .modifyAll(fn) to transform only matching items. Non-matching elements pass through unchanged.