# @fuiste/optics 中文文档

规范地址：https://npmcn.com/package/%40fuiste/optics/

版本：2\.0\.0
npm 元数据更新时间：2026-04-10T22:35:23.058Z
中文译文更新时间：2026-11-15T16:21:38.280Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40fuiste/optics
原文对照：https://npmcn.com/package/%40fuiste/optics/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：59.7 kB，5 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=20\.19\.0
- 运行依赖：0 个
- 首次发布：2025-09-18T16:33:15.408Z
- 最新版本发布：2026-04-10T22:35:22.929Z
- 近 30 天下载量：7274（2026-10-16 至 2026-11-14，npm 官方下载统计）
- 已发布版本数：5（近 12 个月 1 个）

## 中文简介

类型安全、功能性光学(光学、棱镜、转录等),用于不可改变的数据

## 安装

```sh
npm install @fuiste/optics
```

也可以使用：`pnpm add @fuiste/optics`、`yarn add @fuiste/optics`、`bun add @fuiste/optics`

## README

# 图像

类型安全,用于TypeScript中不可变数据的功能光学.

-   **镜头** ——全面注重所需价值
-   **棱镜** - 部分侧重于任择或工会价值
-   **伊苏** ——两种类型之间总,不可逆的测绘
-   **倾斜** —— 聚焦于零或以上的值( 如数组的所有元素)
-   **盖特** ——只读总焦点(计算值/出值)
-   **折叠** ——只读多焦点(摘录后不加修改)

所有光学作品都通过独立自由编曲 `compose` 函数。 四个人类基因组组合器—— `guard`, (中文(简体) ), `at`, (中文(简体) ), `index`,以及 `each` ——涵盖最常见的建筑模式.

## 安装

```bash
# npm
npm install @fuiste/optics

# pnpm
pnpm add @fuiste/optics

# yarn
yarn add @fuiste/optics

# bun
bun add @fuiste/optics
```

## 发展

-   软件包管理器 : `pnpm`
-   支持的节点.js: `>=20.19.0`

## 快开始

### 镜头( 所需数据)

```typescript
import { Lens } from '@fuiste/optics'

type Person = {
  name: string
  age: number
  address: { street: string; city: string }
}

const nameLens = Lens<Person>().prop('name')

const person: Person = { name: 'John', age: 30, address: { street: '123', city: 'NYC' } }

nameLens.get(person) // 'John'
nameLens.set('Jane')(person) // { name: 'Jane', age: 30, address: { ... } }
nameLens.set((name) => name.toUpperCase())(person) // name == 'JOHN'
```

### 棱镜( 可选数据)

```typescript
import { Prism } from '@fuiste/optics'

type Person = {
  name: string
  address?: { street: string; city: string }
}

const addressPrism = Prism<Person>().of({
  get: (p) => p.address,
  set: (address) => (p) => ({ ...p, address }),
})

addressPrism.get({ name: 'A' }) // undefined
addressPrism.set({ street: '456', city: 'LA' })({ name: 'A' })
// => { name: 'A', address: { street: '456', city: 'LA' } }

// Functional updater — no-op when absent
addressPrism.set((addr) => ({ ...addr, city: 'LA' }))({
  name: 'A',
  address: { street: '1', city: 'NYC' },
})
// => { name: 'A', address: { street: '1', city: 'LA' } }
```

### Iso (不可逆地绘图)

```typescript
import { Iso } from '@fuiste/optics'

const numberString = Iso<number, string>({ to: (n) => `${n}`, from: (s) => parseInt(s, 10) })

numberString.to(42) // '42'
numberString.from('7') // 7
```

### 倾斜( 多值)

```typescript
import { Lens, compose, each } from '@fuiste/optics'

type Team = { members: string[] }

const membersLens = Lens<Team>().prop('members')
const eachMember = each<string>()

const allMembers = compose(membersLens, eachMember)

const team: Team = { members: ['Alice', 'Bob'] }

allMembers.getAll(team) // ['Alice', 'Bob']
allMembers.modify((n) => n.toUpperCase())(team)
// => { members: ['ALICE', 'BOB'] }
```

### Getter (计算只读值)

```typescript
import { Lens, Getter, compose } from '@fuiste/optics'

type Person = { firstName: string; lastName: string }
type Team = { lead: Person }

const fullName = Getter<Person, string>((p) => `${p.firstName} ${p.lastName}`)
const leadLens = Lens<Team>().prop('lead')

const leadName = compose(leadLens, fullName)
leadName.get({ lead: { firstName: 'Alice', lastName: 'Smith' } }) // 'Alice Smith'
// leadName has no `set` — it's read-only
```

### 折叠( 只读取许多值)

```typescript
import { Fold } from '@fuiste/optics'

const words = Fold<string, string>((s) => s.split(' '))
words.getAll('hello world') // ['hello', 'world']
```

* * *

## 组成

所有光学都通过独立制作 `compose(outer, inner)` 函数。 返回类型自动确定 :

| 外 内 | **镜头** | **棱镜** | **伊苏** | **倾斜** | **盖特** | **折叠** |
| --- | --- | --- | --- | --- | --- | --- |
| **镜头** | 镜头 | 棱镜 | 镜头 | 倾斜 | 盖特 | 折叠 |
| **棱镜** | 棱镜 | 棱镜 | 棱镜 | 倾斜 | 折叠 | 折叠 |
| **伊苏** | 镜头 | 棱镜 | 伊苏 | 倾斜 | 盖特 | 折叠 |
| **倾斜** | 倾斜 | 倾斜 | 倾斜 | 倾斜 | 折叠 | 折叠 |
| **盖特** | 盖特 | 折叠 | 盖特 | 折叠 | 盖特 | 折叠 |
| **折叠** | 折叠 | 折叠 | 折叠 | 折叠 | 折叠 | 折叠 |

**拇指规则 :**

-   任何东西 **折叠** - 折叠(只读会传染)
-   **盖特** + 部分光学-折叠; **盖特** + 光学合计 + Getter
-   **倾斜** 吸收其他可书写光学 + 倾斜
-   **伊苏** 透明: 其他光学类的获胜
-   **连线 连线** →;其他一切与棱相通

```typescript
import { Lens, Prism, Iso, compose } from '@fuiste/optics'

type Address = { street: string; city: string }
type Person = { name: string; address?: Address }

const addressPrism = Prism<Person>().of({
  get: (p) => p.address,
  set: (address) => (p) => ({ ...p, address }),
})
const cityLens = Lens<Address>().prop('city')

// Prism ∘ Lens => Prism
const cityPrism = compose(addressPrism, cityLens)
cityPrism.get({ name: 'A', address: { street: '1', city: 'NYC' } }) // 'NYC'
cityPrism.get({ name: 'A' }) // undefined
cityPrism.set('LA')({ name: 'A' }) // unchanged (missing path is a no-op)

// Lens ∘ Iso => Lens
type Model = { count: number }
const countLens = Lens<Model>().prop('count')
const numberString = Iso<number, string>({ to: (n) => `${n}`, from: (s) => parseInt(s, 10) })
const countAsString = compose(countLens, numberString)
countAsString.get({ count: 7 }) // '7'
countAsString.set('10')({ count: 7 }) // { count: 10 }
```

### 多步骤链

作曲可以被嵌入深道:

```typescript
import { Lens, compose, each } from '@fuiste/optics'

type Company = { employees: Array<{ name: string; role: string }> }

const employeesLens = Lens<Company>().prop('employees')
const eachEmployee = each<{ name: string; role: string }>()
const empName = Lens<{ name: string; role: string }>().prop('name')

const allEmployeeNames = compose(compose(employeesLens, eachEmployee), empName)

allEmployeeNames.getAll(company) // ['Alice', 'Bob', ...]
allEmployeeNames.modify((n) => n.toUpperCase())(company)
```

* * *

## 组合器

### `guard` ——类型护卫棱镜

从 TypeScript 类型守护创建棱镜。 比手工写作要多得多 `Prism().of(...)` 歧视工会.

```typescript
import { guard, Lens, compose } from '@fuiste/optics'

type Circle = { type: 'circle'; radius: number }
type Square = { type: 'square'; side: number }
type Shape = Circle | Square

const circlePrism = guard<Shape, Circle>((s): s is Circle => s.type === 'circle')

circlePrism.get({ type: 'circle', radius: 5 }) // { type: 'circle', radius: 5 }
circlePrism.get({ type: 'square', side: 4 }) // undefined

// Compose with a lens
const circleRadius = compose(circlePrism, Lens<Circle>().prop('radius'))
circleRadius.get({ type: 'circle', radius: 5 }) // 5
circleRadius.set(10)({ type: 'circle', radius: 5 }) // { type: 'circle', radius: 10 }
```

### `at` ——记录密钥访问

创建以密钥为重点的棱镜 `Record<string, V>`. 回归 `undefined` 键缺失时; 调用时设置/设置.

```typescript
import { at, Lens, compose } from '@fuiste/optics'

type Config = { headers: Record<string, string> }

const headersLens = Lens<Config>().prop('headers')
const authHeader = at<string>('Authorization')

const configAuth = compose(headersLens, authHeader)

configAuth.get({ headers: { Authorization: 'Bearer x' } }) // 'Bearer x'
configAuth.get({ headers: {} }) // undefined
configAuth.set('Bearer y')({ headers: {} })
// => { headers: { Authorization: 'Bearer y' } }
```

### `index` ——阵列元素访问

创建一个侧重于单一数组元素的棱镜. `get` 返回时 `undefined` 当指数离谱的时候 `set` 元素缺失时为无操作.

```typescript
import { index } from '@fuiste/optics'

const second = index<number>(1)

second.get([10, 20, 30]) // 20
second.get([10]) // undefined
second.set(99)([10, 20, 30]) // [10, 99, 30]
second.set(99)([10]) // unchanged
```

### `each` 横向阵列

创建一个横跨 a 的所有元素 `ReadonlyArray<A>`。 。 。 .

```typescript
import { each, compose, Lens } from '@fuiste/optics'

const nums = each<number>()
nums.getAll([1, 2, 3]) // [1, 2, 3]
nums.modify((n) => n * 2)([1, 2, 3]) // [2, 4, 6]
```

* * *

## API 参考

### 类型

```typescript
type Lens<S, A> = {
  _tag: 'lens'
  get: (s: S) => A
  set: (a: A | ((a: A) => A)) => (s: S) => S
}

type Prism<S, A> = {
  _tag: 'prism'
  get: (s: S) => A | undefined
  set: (a: A | ((a: A) => A)) => (s: S) => S
}

type Iso<S, A> = {
  _tag: 'iso'
  to: (s: S) => A
  from: (a: A) => S
}

type Traversal<S, A> = {
  _tag: 'traversal'
  getAll: (s: S) => ReadonlyArray<A>
  modify: (f: (a: A) => A) => (s: S) => S
}

type Getter<S, A> = {
  _tag: 'getter'
  get: (s: S) => A
}

type Fold<S, A> = {
  _tag: 'fold'
  getAll: (s: S) => ReadonlyArray<A>
}

type Optic<S, A> = Lens<S, A> | Prism<S, A> | Iso<S, A> | Traversal<S, A> | Getter<S, A> | Fold<S, A>
```

### 工厂

```typescript
// Lens factory — use .prop to focus on a property key
Lens<S>().prop<K extends keyof S>(key: K): Lens<S, S[K]>

// Prism factory — use .of to build from get/set
Prism<S>().of<A>({ get, set }): Prism<S, A>

// Direct constructors
Iso<S, A>({ to, from }): Iso<S, A>
Traversal<S, A>({ getAll, modify }): Traversal<S, A>
Getter<S, A>(get: (s: S) => A): Getter<S, A>
Fold<S, A>(getAll: (s: S) => ReadonlyArray<A>): Fold<S, A>
```

### 独立职能

```typescript
// Universal composition — 36 overloads, result type inferred from inputs
compose<S, A, B>(outer: Optic<S, A>, inner: Optic<A, B>): Optic<S, B>

// Type-guard prism
guard<S, A extends S>(predicate: (s: S) => s is A): Prism<S, A>

// Record key prism
at<V>(key: string): Prism<Record<string, V>, V>

// Array index prism
index<A>(idx: number): Prism<ReadonlyArray<A>, A>

// Array element traversal
each<A>(): Traversal<ReadonlyArray<A>, A>
```

### 工具类型

```typescript
InferSource<O extends Optic>  // Extract the S from any optic
InferTarget<O extends Optic>  // Extract the A from any optic
```

* * *

## 行为说明

-   `Lens#set` 财务报告和审定财务报表 `Prism#set` 都接受一个值或 `(a) => a` 更新器功能并返回新对象。 原作从未变异.
-   可书写光学在公共设置签名中保存了呼叫者的源形状,以与收缩状态相兼容.
-   `Prism#get` 可能返回 `undefined`在由构成的棱镜中,任何缺失的外分枝都会导致 `undefined`。 。 。 .
-   `Prism#set` 在外分枝缺失的情况下 **无 -op** 默认。 函数更新器缺少时也是无操作的 .
-   **例外——棱镜-伊索**:通过外棱镜提供具体价值 `set` 即使当 `get` 返回时 `undefined`,因为Iso总是可以构造中间值. 函数更新器缺失时仍为禁用 .
-   `Traversal#modify` 将函数应用于每个焦点元素。 对于通过缺失的棱柱分枝而构成的曲面,修改是没有的.
-   当库能发现焦点值没有改变时,未更改的更新会保留引用身份.
-   `Getter` 财务报告和审定财务报表 `Fold` ——他们没有 `set` 或者说 `modify`。用只读光学制取任何光学效果.

* * *

## 最佳做法

-   小光学的构成优于一个大定制的取取取器/取取取器
-   使用 `guard` 歧视的工会,而不是手工工会 `Prism().of`
-   使用 `each` + 键 `compose` 用于散装阵列操作
-   使用 `index()` 用于单个阵列元素和 `at()` 用于记录/映射密钥
-   使用 `Getter` 对于不应固定的衍生值
-   将光学视为纯度: 绝不改变内部输入 `set`
-   对于数组,偏好 `each()` 用于所有元素或 `index(i)` 一个元素. `Lens<T[]>().prop(index)` 仍然支持兼容性.

## 常见问题

### @fuiste/optics 是什么？

类型安全、功能性光学\(光学、棱镜、转录等\),用于不可改变的数据

### 如何安装 @fuiste/optics？

在项目目录运行 npm install @fuiste/optics，或使用 pnpm add / yarn add / bun add。

### @fuiste/optics 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @fuiste/optics 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @fuiste/optics 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20\.19\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @fuiste/optics 可以商用吗？

@fuiste/optics 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @fuiste/optics 的下载量有多少？

根据 npm 官方下载统计，@fuiste/optics 在 2026/10/16 – 2026/11/14 这 30 天内被下载 7,274 次，日均约 242 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @fuiste/optics 还在维护吗？

最新版本 2\.0\.0 发布于 2026/04/11（7 个月前）；至今共发布 5 个版本，其中过去 12 个月发布了 1 个；首次发布于 2025/09/19。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

