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.