# @fp-ts/optic 中文文档

规范地址：https://npmcn.com/package/%40fp-ts/optic/

版本：0\.25\.0
npm 元数据更新时间：2024-09-20T06:10:48.152Z
中文译文更新时间：2026-11-15T11:00:57.730Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40fp-ts/optic
原文对照：https://npmcn.com/package/%40fp-ts/optic/?lang=original
项目主页：https://github.com/fp-ts/optic#readme
源码仓库：https://github.com/fp-ts/optic

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

- 包体积（解压后）：170 kB，74 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：@effect/typeclass ^0\.27\.0，effect ^3\.8\.0
- 首次发布：2022-11-25T14:17:35.100Z
- 最新版本发布：2024-09-20T06:10:47.940Z
- 近 30 天下载量：8078（2026-10-16 至 2026-11-14，npm 官方下载统计）
- 已发布版本数：32（近 12 个月 0 个）

## 中文简介

### [![](https://npmcn.com/package/%40fp-ts/optic/docs/fp-ts-logo.png)](https://fp-ts.github.io/optic/)

## 安装

```sh
npm install @fp-ts/optic
```

也可以使用：`pnpm add @fp-ts/optic`、`yarn add @fp-ts/optic`、`bun add @fp-ts/optic`

## README

### [![](https://npmcn.com/package/%40fp-ts/optic/docs/fp-ts-logo.png)](https://fp-ts.github.io/optic/)

移植 [齐奥光学](https://github.com/zio/zio-optics) 到类型脚本

[![npm downloads](https://img.shields.io/npm/dm/@fp-ts/optic.svg)](https://www.npmjs.com/package/@fp-ts/optic)

```mermaid
flowchart TD
  Iso --> Lens
  Iso --> Prism
  Lens --> ReversedPrism
  ReversedPrism --> Optional
  Prism --> Optional
  Optional --> Getter
  Optional --> Setter
  Getter --> Optic
  Setter --> Optic
```

# 特征

-   **光子的统一代表**。所有光学的构成方式相同,因为它们都是同一数据类型的实例(`Optic`(中文(简体) )
-   **一体化**。用于 `effect` 数据结构,例如 `Option` 财务报告和审定财务报表 `Either`。 。 。 .

## 导言

`@fp-ts/optic` 是一个库,可以方便地根据光学的单一表现来修改较大数据结构的部件,作为取出器和定出器的组合.

`@fp-ts/optic` 具有光学的统一代表性,深度 `effect` 集成, 帮助错误消息 .

# 信贷和担保

这个图书馆受到以下项目的启发:

-   [齐奥光学](https://github.com/zio/zio-optics)
-   [单管](https://github.com/gcanti/monocle-ts)

非常感谢我的赞助商,他们开发了 `@fp-ts/optic` 也许吧.

如果你还想 **成为提案人** 确保这个图书馆继续改进和接受维护 [GitHub 赞助者简介](https://github.com/sponsors/gcanti?o=sd&sc=t)

## 所需资源

-   类型脚本 5.4 或更新
-   这个 `strict` 启用您的旗帜 `tsconfig.json` 文件

```
{
  // ...
  "compilerOptions": {
    // ...
    "strict": true
  }
}
```

## 开始

安装 **阿尔法** 版本 :

```
npm install @fp-ts/optic
```

**3⁄4 ̄ ̧漯B**。本套件的发布主要是为了接收早期反馈,对于贡献者来说,在这个开发阶段,我们不能保证APIs的稳定性,认为每个版本都包含断续续的更改.

一旦安装了库,您可以从库中导入必要的类型和功能 `@fp-ts/optic` 模块.

```ts
import * as Optic from "@fp-ts/optic";
```

# 内容提要

假设我们有个员工 并且我们得给他公司街名上的第一个角色.

```ts
import * as Option from "effect/Option";

interface Street {
  readonly num: number;
  readonly name: Option.Option<string>;
}
interface Address {
  readonly city: string;
  readonly street: Street;
}
interface Company {
  readonly name: string;
  readonly address: Address;
}
interface Employee {
  readonly name: string;
  readonly company: Company;
}

const from: Employee = {
  name: "john",
  company: {
    name: "awesome inc",
    address: {
      city: "london",
      street: {
        num: 23,
        name: Option.some("high street"),
      },
    },
  },
};

const to: Employee = {
  name: "john",
  company: {
    name: "awesome inc",
    address: {
      city: "london",
      street: {
        num: 23,
        name: Option.some("High street"),
      },
    },
  },
};
```

让我们看看我们能做什么 `@fp-ts/optic`

```ts
import * as Optic from "@fp-ts/optic";
import * as StringOptic from "@fp-ts/optic/String";
import * as String from "effect/String";
import * as assert from "node:assert";

const _firstChar: Optic.Optional<Employee, string> = Optic.id<Employee>()
  .at("company")
  .at("address")
  .at("street")
  .at("name")
  .some()
  .compose(StringOptic.index(0));

const capitalizeName = Optic.modify(_firstChar)(String.toUpperCase);

assert.deepStrictEqual(capitalizeName(from), to);
```

# 理解视觉

`@fp-ts/optic` 其基础是光学的单一表示,作为取出器和定出器的组合.

```ts
export interface Optic<
  in GetWhole,
  in SetWholeBefore,
  in SetPiece,
  out GetError,
  out SetError,
  out GetPiece,
  out SetWholeAfter,
> {
  readonly getOptic: (
    GetWhole: GetWhole
  ) => Either<readonly [GetError, SetWholeAfter], GetPiece>;
  readonly setOptic: (
    SetPiece: SetPiece
  ) => (
    SetWholeBefore: SetWholeBefore
  ) => Either<readonly [SetError, SetWholeAfter], SetWholeAfter>;
}
```

获取器可以使用一些更大的类型结构 `GetWhole` 并获得它的一部分类型 `GetPiece`。它可能因类型错误而失败 `GetError` 因为我们试图得到的部分 可能不存在 在更大的结构.

摆放器有它的能力,因为它有些类型 `SetPiece` 和原类型结构 `SetWholeBefore`,返回新的类型结构 `SetWholeAfter`设置会因类型错误而失败 `SetError` 因为我们试图设置的棋子 可能不存在的结构.

## 镜头

A 类 `Lens` 是一种访问产品类型领域的光学技术,例如tuple或struct.

这个 `GetError` 类型 `Lens` 实值 `never` 因为我们总能得到一个产品类型的领域。 这个 `SetError` 类型也是 `never` 因为我们总能把产品类型的领域设置到一个新的值.

在这种情况下 `GetWhole`, (中文(简体) ), `SetWholeBefore`,以及 `SetWholeAfter` 类型相同,并代表产品类型。 这个 `GetPiece` 财务报告和审定财务报表 `SetPiece` 类型也是相同的,并代表字段.

因此,我们:

```ts
export interface Lens<in out S, in out A>
  extends Optic<S, S, A, never, never, A, S> {}
```

简化的签名是:

```ts
export interface Lens<in out S, in out A> {
  readonly getOptic: (s: S) => Either<never, A>;
  readonly setOptic: (a: A) => (s: S) => Either<never, S>;
}
```

这完全符合我们上面的描述。 透镜是一种光学,我们总能得到更大的结构的一部分, 并且赋予一个原始的结构,我们总能在那个结构中设定一个新的价值.

## 棱镜

A 类 `Prism` 是一种光学,可以访问一个总和型的相机,例如: `Left` 或者说 `Right` 案件数量 `Either`。 。 。 .

用棱镜从更大的数据结构中获取一部分可能会失败,因为我们试图访问的案例可能不存在. 例如,我们可能试图进入一个 `Either` 但其中之一其实是 `Left`。 。 。 .

我们使用数据类型 `Error` 来模拟不同的方式 获取或设定 光学会失败。 所以说 `GetError` 棱镜类型 `Error`。 。 。 .

这个 `SetError` 棱镜类型 `never` 因为鉴于某种产品类型的一种情况,我们总能返回一种产品类型的新价值,因为产品类型的每一种情况都是产品类型的一种情况.

棱镜也不同于镜头,因为我们不需要任何原始结构来设定. 一种产品类型只包括它的案例, 所以如果我们有我们想要设定的新的案例价值, 我们可以仅仅使用这个价值, 而不需要原始的结构.

我们用 `unknown` 联 合 国 `SetWholeBefore` 类型,表示我们不需要任何原始结构来设置新值.

因此,棱镜的定义是:

```ts
export interface Prism<in out S, in out A>
  extends Optic<S, unknown, A, Error, never, A, S> {}
```

而简化的签名是:

```ts
export interface Prism<in out S, in out A> {
  readonly getOptic: (s: S) => Either<Error, A>;
  readonly setOptic: (a: A) => (s: unknown) => Either<never, S>;
}
```

这同样符合我们的描述。 棱镜是一种光学,我们也许无法获得一个值,但总是可以设定一个值,事实上不需要任何原始结构来设定.

## 其它

`@fp-ts/optic` 支持多种其他光学:

-   **可选**。一个 `Optional` 是一种光学,它访问一个更大的结构的一部分,其中访问的部分可能不存在,而且该结构不仅包含该部分。 两者 `GetError` 财务报告和审定财务报表 `SetError` 类型是 `Error` 因为这个部分在结构中可能不存在,而设置中确实需要原始结构,因为它包含的不仅仅是这个部分.
-   **伊苏**。一个 `Iso` 是一个光学的,它访问一个结构的一部分, 结构中除了部分之外,什么都不是。 两者 `GetError` 财务报告和审定财务报表 `SetError` 类型是 `never` 编辑 `SetWholeBefore` 类型是 `unknown`。 。 。 .
-   **盖特**A级 `Getter` 光学只允许获得一个值。 这个 `SetWholeBefore` 财务报告和审定财务报表 `SetPiece` 类型是 `never` 因为它永远无法设置.
-   **编辑器**A级 `Setter` 是一个只允许设置值的光学。 这个 `GetWhole` 类型是 `never` 因为它不可能永远得到.

每种光学的多态性版本也比较多,使得数据结构的种类和前后部分不同. 例如,a `PolyPrism` 可以让我们找到一个合适的案子 `Either<A, B>` 设置一个 `C` 要返回的数值 `Either<A, C>`。 。 。 .

# 计费表

## 透视构造器

| 图像 | 名称 | 鉴于 | 改为: |
| --- | --- | --- | --- |
| 伊苏 | 实值 | `S => A`, (中文(简体) ), `A => S` | `Iso<S, A>` |
|  | 编号 |  | `Iso<S, S>` |
| 镜头 | 镜头 | `S => A`, (中文(简体) ), `A => S => S` | `Lens<S, A>` |
|  | 时间 | `Key` | `Lens<S, S[Key]>` |
|  | 选择 | `Key` | `Lens<S, Pick<S, Key>>` |
|  | 删除 | `Key` | `Lens<S, Omit<S, Key>>` |
| 棱镜 | 棱镜 | `S => Either<Error, A>`, (中文(简体) ), `A => S` | `Prism<S, A>` |
|  | 多边棱镜 | `S => Either<[Error, T], A>`, (中文(简体) ), `B => T` | `PolyPrism<S, T, A, B>` |
|  | 骗局 |  | `Prism<A[], [A, A[]]>` |
|  | 非无 |  | `Prism<A, NonNullable<A>>` |
|  | 有点 |  | `Prism<Option<A>, A>` |
|  | 过滤器 | `Predicate<S>` | `Prism<S, S>` |
|  | 过滤器 | `Refinement<S, A>` | `Prism<S, A>` |
| 可选 | 选项 | `S => Either<Error, A>`, (中文(简体) ), `A => S => Either<Error, S>` | `Optional<S, A>` |
|  | 多选项 | `S => Either<[Error, T], A>`, (中文(简体) ), `B => S => Either<[Error, T], T>` | `PolyOptional<S, T, A, B>` |
|  | 指数 | `number` | `Optional<A[], A>` |
|  | 键 | `string` | `Optional<{ []: A }, A>` |
|  | 头 |  | `Optional<A[], A>` |
|  | 尾声 |  | `Optional<A[], A[]>` |
|  | 找到第一个 | `Predicate<A>` | `Optional<A[], A>` |
|  | 找到第一个 | `Refinement<A, B>` | `Optional<A[], B>` |

## Getter / Stetter APIs 图像

| 名称 | 鉴于 | 改为: |
| --- | --- | --- |
| 起来 | `Lens<S, A>`, (中文(简体) ), `S` | `A` |
| 解码 | `Prism<S, A>`, (中文(简体) ), `S` | `Either<Error, A>` |
| 编码 | `Prism<S, A>`, (中文(简体) ), `A` | `S` |
| 获得 Ordify 编辑 | `PolyOptional<S, T, A, B>`, (中文(简体) ), `S` | `Either<T, A>` |
| 修改 | `Optional<S, A>`, (中文(简体) ), `A => A` | `S => S` |
| 替换 | `Setter<S, A>`, (中文(简体) ), `A`, (中文(简体) ), `S` | `S` |
| 替换选项 | `Setter<S, A>`, (中文(简体) ), `A`, (中文(简体) ), `S` | `Option<S>` |
| 获取选项 | `Getter<S, A>`, (中文(简体) ), `S` | `Option<A>` |

# 基本用途

## 编号

这个 `id` 光学是一种代表身份函数的特殊光学,它简单地返回它的输入而不变. 可以认为是光学的"基案",从中可以建造出更复杂的光学.

这个 `id` 光学被定义为单通类型,这意味着它只有一个可能的值. 这使得它很容易成为建造更大型光学的起点,因为它不需要任何参数或配置.

```ts
import * as Optic from "@fp-ts/optic";

interface Whole {
  readonly a: string;
  readonly b: number;
  readonly c: boolean;
}

// create an iso that focuses on the 'Whole' data structure
const _a: Optic.Iso<Whole, Whole> = Optic.id<Whole>();
```

## 编曲

这个 `compose` 方法是一种实用函数,可以将两个或两个以上的光学组合成一个光学.

```ts
import { pipe } from "effect";
import * as Optic from "@fp-ts/optic";

// This is the type of the data structure that the lens will be operating on.
interface Whole {
  readonly a: string;
  readonly b: number;
  readonly c: boolean;
}

// This creates a lens that focuses on the 'a' field within the 'Whole' object.
const _a: Optic.Lens<Whole, string> =
  // The 'id' function creates an identity lens for the 'Whole' type.
  Optic.id<Whole>()
    // The 'compose' method combines the identity lens with an 'at' lens,
    // which selects the 'a' field within the 'Whole' object.
    .compose(Optic.at("a"));

// Now we can use the '_a' lens to view and modify the 'a' field of a 'Whole' object.

const whole: Whole = {
  a: "foo",
  b: 42,
  c: true,
};

// Use the 'get' function to view the 'a' field of the 'whole' object.
const result: string = pipe(whole, Optic.get(_a)); // returns "foo"

// Use the 'replace' function to update the 'a' field of the 'whole' object.
const updated: Whole = pipe(whole, Optic.replace(_a)("bar")); // returns { a: "bar", b: 42, c: true }
```

## 时间

这个 `at` 方法是一种实用函数,它创造了一个光学功能,它侧重于数据结构内的特定字段.

```ts
import { pipe } from "effect";
import * as Optic from "@fp-ts/optic";

// This is the type of the data structure that the lens will be operating on.
interface Whole {
  readonly a: string;
  readonly b: number;
  readonly c: boolean;
}

// This creates a lens that focuses on the 'a' field within the 'Whole' object.
const _a: Optic.Lens<Whole, string> =
  // The 'id' function creates an identity lens for the 'Whole' type.
  Optic.id<Whole>()
    // The 'at' method selects the 'a' key within the 'Whole' object,
    // resulting in a lens that is focused on that field.
    .at("a");

// Now we can use the '_a' lens to view and modify the 'a' field of a 'Whole' object.

const whole: Whole = {
  a: "foo",
  b: 42,
  c: true,
};

// Use the 'get' function to view the 'a' field of the 'whole' object.
const result: string = pipe(whole, Optic.get(_a)); // returns "foo"

// Use the 'replace' function to update the 'a' field of the 'whole' object.
const updated: Whole = pipe(whole, Optic.replace(_a)("bar")); // returns { a: "bar", b: 42, c: true }
```

## 选择

这个 `pick` 方法是一种实用函数,它创建了光学,侧重于数据结构内的一组密钥.

```ts
import { pipe } from "effect";
import * as Optic from "@fp-ts/optic";

// This is the type of the data structure that the lens will be operating on.
interface Whole {
  readonly a: string;
  readonly b: number;
  readonly c: boolean;
}

// This creates a lens that focuses on the 'a' and 'b' fields within the 'Whole' object.
const _ab: Optic.Lens<Whole, { readonly a: string; readonly b: number }> =
  // The 'id' function creates an identity lens for the 'Whole' type.
  Optic.id<Whole>()
    // The 'pick' method selects the 'a' and 'b' keys within the 'Whole' object,
    // resulting in a lens that is focused on those fields.
    .pick("a", "b");

// Now we can use the '_ab' lens to view and modify the 'a' and 'b' fields of a 'Whole' object.

const whole: Whole = {
  a: "foo",
  b: 42,
  c: true,
};

// Use the 'get' function to view the 'a' and 'b' fields of the 'whole' object.
const result: { readonly a: string; readonly b: number } = pipe(
  whole,
  Optic.get(_ab)
); // returns { a: "foo", b: 42 }

// Use the 'replace' function to update the 'a' and 'b' fields of the 'whole' object.
const updated: Whole = pipe(whole, Optic.replace(_ab)({ a: "bar", b: 23 })); // returns { a: "bar", b: 23, c: true }
```

## 删除

这个 `omit` 方法是一个工具函数,它创建一个将一组密钥排除在结构外的透镜。 当您想要专注于一个数据结构的子集而忽略某些字段时,这可能会有用.

```ts
import { pipe } from "effect";
import * as Optic from "@fp-ts/optic";

interface Whole {
  readonly a: string;
  readonly b: number;
  readonly c: boolean;
}

// This creates a lens that focuses on the 'a' and 'c' fields within the 'Whole' object.
const _ac: Optic.Lens<Whole, { readonly a: string; readonly c: boolean }> =
  // The 'id' function creates an identity lens for the 'Whole' type.
  Optic.id<Whole>()
    // The 'omit' method excludes the 'b' key within the 'Whole' object,
    // resulting in a lens that is focused on the 'a' and 'c' fields.
    .omit("b");

// Now we can use the '_ac' lens to view and modify the 'a' and 'c' fields of a 'Whole' object.

const whole: Whole = {
  a: "foo",
  b: 42,
  c: true,
};

// Use the 'get' function to view the 'a' and 'c' fields of the 'whole' object.
const result: { readonly a: string; readonly c: boolean } = pipe(
  whole,
  Optic.get(_ac)
); // returns { a: "foo", c: true }

// Use the 'replace' function to update the 'a' and 'c' fields of the 'whole' object.
const updated: Whole = pipe(whole, Optic.replace(_ac)({ a: "bar", c: false })); // returns { a: "bar", b: 42, c: false }
```

## 过滤器

这个 `filter` 方法是一种实用函数,它创造了一个光学函数,它侧重于一个数据结构的元素,与指定的上游相匹配.

```ts
import { pipe } from "effect";
import * as Optic from "@fp-ts/optic";
import type { Option } from "effect/Option";

// This is the type of the data structure that the prism will be operating on.
interface Whole {
  readonly a: number;
}

// This creates an `Optional` that focuses on the 'a' field within the 'Whole' object,
// and only includes values that are even numbers.
const _evenA: Optic.Optional<Whole, number> =
  // The 'id' function creates an identity prism for the 'Whole' type.
  Optic.id<Whole>()
    // The 'at' method selects the 'a' key within the 'Whole' object,
    // resulting in a `Lens` that is focused on that field.
    .at("a")
    // The 'filter' method only includes values that are even numbers.
    .filter((a) => a % 2 === 0);

// Now we can use the '_evenA' `Optional` to view and modify the 'a' field of a 'Whole' object,
// but only if the value is an even number.

const whole: Whole = {
  a: 2,
};

// Use the 'getOption' function to view the 'a' field of the 'whole' object.
const result: Option<number> = pipe(whole, Optic.getOption(_evenA)); // returns some(2)

// Use the 'replace' function to update the 'a' field of the 'whole' object.
const updated: Whole = pipe(whole, Optic.replace(_evenA)(4)); // returns { a: 4 }
```

## 非无

这个 `nonNullable` 方法是一个创建 `Prism` ,侧重于无效类型的不可变值。 如果您想要操纵或提取无效类型的值, 但想要忽略 `null` 数值.

```ts
import { pipe } from "effect";
import * as Optic from "@fp-ts/optic";
import type { Option } from "effect/Option";

const _nonNullString: Optic.Prism<string | null, string> = Optic.id<
  string | null
>().nonNullable();

const result1: Option<string> = pipe("foo", Optic.getOption(_nonNullString)); // returns some("foo")
const result2: Option<string> = pipe(null, Optic.getOption(_nonNullString)); // returns none
```

## 有点

这个 `some` 方法是一种效用函数,可以创建一个侧重于光学的光学函数 `Some` 情况 `Option` 数据类型。 此光学允许您查看并修改其中包含的值 `Some` 情况 `Option`。 。 。 .

```ts
import { pipe } from "effect";
import * as Option from "effect/Option";
import * as Optic from "@fp-ts/optic";

// This creates a prism that focuses on the 'Some' case of the 'Option<number>' object.
const _some: Optic.Prism<Option.Option<number>, number> = Optic.id<
  Option.Option<number>
>().some();

const option: Option.Option<number> = Option.some(42);

const result: Option.Option<number> = pipe(option, Optic.getOption(_some)); // returns some(42)

const updated: Option.Option<number> = pipe(option, Optic.replace(_some)(23)); // returns some(23)
```

## 指数

这个 `index` 方法创建 `Optional` 光学,其重点是a `ReadonlyArray`编辑 `Optional` 光学允许您在指定的索引中查看值,或者 `None` 如果索引不存在。 你也可以使用这个 `Optional` 光学可以更新指定索引中的值,如果存在的话.

```ts
import { pipe } from "effect";
import * as Optic from "@fp-ts/optic";
import type { Option } from "effect/Option";

const _index2: Optic.Optional<ReadonlyArray<number>, number> = Optic.id<
  ReadonlyArray<number>
>().index(2);

const arr: ReadonlyArray<number> = [1, 2, 3, 4];

const result: Option<number> = pipe(arr, Optic.getOption(_index2)); // some(3)
const updated1: ReadonlyArray<number> = pipe(arr, Optic.replace(_index2)(42)); // [1, 2, 42, 4]
const updated2: ReadonlyArray<number> = pipe(arr, Optic.replace(_index2)(10)); // [1, 2, 10, 4]
const updated3: ReadonlyArray<number> = pipe([], Optic.replace(_index2)(10)); // []
```

## 键

这个 `key` 方法是允许您创建 `Optional` 以索引签名的特定密钥(有字符串索引签名的类型)为重点的光学.

```ts
import { pipe } from "effect";
import type { Option } from "effect/Option";
import * as Optic from "@fp-ts/optic";

interface Data {
  readonly [key: string]: number;
}

// Create an Optional optic that focuses on the 'foo' key.
const _foo: Optic.Optional<Data, number> = Optic.id<Data>().key("foo");

const data: Data = {
  foo: 1,
  bar: 2,
};

// Use the 'getOption' function to view the value of the 'foo' key.
const fooValue: Option<number> = pipe(data, Optic.getOption(_foo)); // returns some(1)

// Use the 'replace' function to update the value of the 'foo' key.
const updatedData: Data = pipe(data, Optic.replace(_foo)(10)); // returns { foo: 10, bar: 2 }
```

# 文档

-   [API 参考](https://fp-ts.github.io/optic/)

# 许可证

《麻省理工学院许可证》

## 常见问题

### 如何安装 @fp-ts/optic？

在项目目录运行 npm install @fp-ts/optic，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@effect/typeclass（^0\.27\.0）、effect（^3\.8\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @fp-ts/optic 支持 TypeScript 吗？

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

### @fp-ts/optic 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @fp-ts/optic 可以商用吗？

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

### @fp-ts/optic 的下载量有多少？

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

### @fp-ts/optic 还在维护吗？

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

