# @caverar/ts-entity 中文文档

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

版本：1\.4\.0
npm 元数据更新时间：2026-11-05T17:01:05.592Z
中文译文更新时间：2026-11-09T13:11:14.828Z
软件包许可：GPL-3\.0-only

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

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

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

- 包体积（解压后）：149 kB，6 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=20
- 运行依赖：0 个
- peer 依赖：typescript ^6\.0\.3
- 首次发布：2026-10-19T22:17:18.112Z
- 最新版本发布：2026-11-05T17:01:05.440Z
- 近 30 天下载量：2617（2026-10-09 至 2026-11-07，npm 官方下载统计）
- 已发布版本数：16（近 12 个月 16 个）

## 中文简介

类型安全域实体具有schema验证,状态过渡,和序列化.

## 安装

```sh
npm install @caverar/ts-entity
```

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

## README

# @caverar/ts-实体

用于TypeScript的类型安全域实体,具有schema验证,明确状态过渡,和序列化.

## 安装

```sh
npm install @caverar/ts-entity zod
```

类型脚本 `^6.0.3` 是同级依赖。 软件包使用 [标准Schema](https://standardschema.dev/) 界面,因此您可以修改另一个兼容的验证库,而不是Zod.

## 快开始

```ts
import * as z from 'zod'
import {
  EntityFactory,
  type EntityMetaStatusVariants,
  type EntityFlatSnapshot,
  type EntitySelf,
} from '@caverar/ts-entity'

const factory = new EntityFactory({
  dateFormat: 'Date',
  id: {
    idSchema: z.uuid(),
    idGenerator: () => crypto.randomUUID(),
  },
  fieldsSchemasGenerator: (schemas) =>
    Object.assign({}, ...(schemas as any).map((schema: z.ZodObject) => schema.shape)),
  mergeSchemaGenerator: (schemas) => z.union(schemas as any),
})

const UserBase = factory.createAbstractEntity({
  draft: {
    schema: z.object({
      email: z.email(),
      name: z.string().min(1),
    }),
    mutatesTo: ['draft', 'active'],
  },
  active: {
    schema: z.object({
      email: z.email(),
      name: z.string().min(1),
      activatedAt: z.date(),
    }),
    mutatesTo: [],
  },
})

class User extends UserBase {
  activate(this: EntitySelf<User, 'draft'>) {
    return this.mutateEntity({ activatedAt: new Date() }, 'active')
  }
}

const result = User.createEntity({ email: 'ada@example.com', name: 'Ada' }, 'draft')

if (!result.isOk) {
  throw new Error('Invalid user data')
}

const user = result.value
console.log(user.id, user.data.email)

// Use EntityMetaStatusVariants for a value whose current domain state varies.
// `metaStatus` narrows the union to its state-specific data and methods.
function inspectUser(entity: EntityMetaStatusVariants<User>) {
  if (entity.metaStatus === 'draft') {
    console.log(entity.data.email)
  } else {
    console.log(entity.data.activatedAt)
  }
}

inspectUser(user)

// A snapshot is also assignable to the merged shape accepted by restoreEntity().
const flatSnapshot: EntityFlatSnapshot<User> = user.toSnapshot()

const activation = user.activate()
if (activation.isOk) {
  console.log(activation.value.metaStatus) // 'active'
}
```

`toSnapshot()` 保存当前状态的形状并返回 a `{ meta, data }` 工会 歧视 `metaStatus`它接受 `{ target: 'json' }` 将日期等值序列化 以及JSON存储的硬币 见 [选择输出](https://npmcn.com/package/%40caverar/ts-entity/#readme-choosing-an-output) 何时使用 相对于其他系列化方法.

## 选择输出

实体揭露出三个集团的API. 选谁消耗结果.

**运行时间序列化(情报方法)**

| 方法 | 消费者 | 形状 | `version` | 品牌 |
| --- | --- | --- | --- | --- |
| `toSnapshot()` | 简单寄存器; 反向 `restoreEntity()` | `{ meta, data }`歧视 `metaStatus` | 包含 | 删除 |
| `toPersistenceChanges()` | 只写已改变内容的仓库 | `{ persistenceStatus, meta, set, unset }` | 包含 | 删除 |
| `toDTO()` | 使用大小写输入/输出、其他限定上下文、切入点 | 平面对象:元和一级数据 | 从未曝光 | 删除; `keepBrands: true` 保留它们(仅类型) |

三个都接受 `{ target: 'json' }`。 。 。 . `toDTO()` 还接受 `omit` (任何密钥,但 `metaStatus`, (中文(简体) ), 并且不会泄露实体本身.

**建筑和重建(静态方法)**

| 方法 | 目的 |
| --- | --- |
| `createEntity(data, metaStatus, meta?)` | 开始一个新的生命周期( E)`persistenceStatus: 'new'`, (中文(简体) ), `version: 1`(中文(简体) ) |
| `restoreEntity({ meta, data })` | 重建一个 `unchanged` 储存快照的基线; `data` 使用合并形状 |

**类型助手**

| 类型 | 说明 |
| --- | --- |
| `EntitySnapshot<E, Target, States>` | 返回类型 `toSnapshot()` |
| `EntityFlatSnapshot<E, Target, States>` | 与每个州合并的快照( 特定州字段可选); 形状 `restoreEntity()` 投入和数据库预测 |
| `EntityPersistenceChanges<...>` | 返回类型 `toPersistenceChanges()` |
| `EntityDTO<E, States, Omitted, Target>` | 返回类型 `toDTO()`,无品牌 `metaStatus` |
| `EntityBrandedDTO<...>` | 与 `EntityDTO`保留品牌`toDTO({ keepBrands: true })`(中文(简体) ) |
| `EntityRawDTO<...>` | `EntityDTO` 平整成一个跨州对象,用于手动 DTO/类型构造 |
| `EntityPickDTO<E, States, Keys>` | 选取平面 DTO 的密钥, 用于大小写输入 |

```ts
type AccountResponse = EntityDTO<Account, 'active' | 'frozen', 'createdAt', 'json'>
const response: AccountResponse = account.toDTO({ target: 'json', omit: ['createdAt'] })
```

## 持久性和乐观的货币

实体曝光 `persistenceStatus` (单位:千美元)`new`, (中文(简体) ), `updated`,或 `unchanged`和数字 `version`。 。 。 . 他们让一个寄存器一起选择一个插入,一个乐观的更新,或者没有写入. 这些价值 描述内存持久性生命周期;它们本身不执行数据库操作.

### 创建新实体

`User.createEntity(data, state)` 验证初始数据并返回新实体 `persistenceStatus: 'new'` 财务报告和审定财务报表 `version: 1`在第一个插入之前的进一步突变 `new` 在第一版中坚持 `INSERT`,包括版本1;不将其视为更新. 只有创造不能拯救它.

对于不属于单一数据库的虚拟实体,通过可选元数据作为第三个 参数 : `User.createEntity(data, state, { id, createdAt, updatedAt })`。每个密钥都是可选的. 一个不见了 `id` 生成; 提供 `id` 对id schema(无效的 ids) 进行验证 返回时 `INVALID_DATA`) (中文(简体) ). 失踪日期默认为现在,以及 `updatedAt` 默认为 `createdAt`。 。 。 .

### 改变一个实体

`mutateEntity()` 被域方法使用并返回一个新的不可变实体; 源实例 不变。 成功突变后:

-   A 类 `new` 实体留下来 `new` 在版本1中,无论插入前变异多少次.
-   第一个变种a `unchanged` 实体标出结果 `updated` 并递增 一个版本.
-   仍在持续期间的进一步突变 `updated` 保留这个版本。 这样可以多次运行 更改构成一个编辑周期和一个数据库更新.
-   计划验证失败返回 `INVALID_DATA`;不产生变异实体.

例如,如果加载实体为第4版,其第一次突变产生第5版. 再来 该周期的突变仍为第五版. 对于乐观的更新,请使用上一个版本作为 比较条件和实体的版本作为写入的值:

```sql
UPDATE users
SET name = :name, version = :newVersion
WHERE id = :id AND version = :expectedVersion;
```

对于一个实体,第5版,设置 `newVersion = 5` 财务报告和审定财务报表 `expectedVersion = 4` (相当于, `newVersion = expectedVersion + 1`) (中文(简体) ).

将影响零行的更新作为货币冲突处理: 另一位写入器已更改或 删除了行。 不要用静默替换实体的版本来标记实体清理或重试; 重新装入 最新的快照,并按照应用程序的规则解决冲突。 一个实体 `persistenceStatus: 'unchanged'` 可被仓库跳过.

### 描述持久性变化

`toPersistenceChanges()` 返回包含当前元数据的数据库不可知描述符,并 存储器可能选择写入的数据。 它不执行查询或要求寄存器到 使用特定的持久性战略:

-   `new`数字 : `set` 包含所有当前实体数据,作为插入的值.
-   `updated`数字 : `set` 包含有最新值的已触动字段; `unset` 包含已删除的字段 从当前数据中,例如当状态过渡去除特定状态的字段时.
-   `unchanged`: 两者 `set` 财务报告和审定财务报表 `unset` 为空.

触摸过的田地累积 `restoreEntity()`。如果一个字段更改,然后返回,则 保留在 `set` 它的最新价值。 仓库可以使用此描述符来避免写入 没有修改的字段,或者忽略它,而是坚持一个完整的快照。 库没有映射 用于数据库列或决定数据库如何代表未设置的字段的实体字段。 更改为 按顶级实体字段报告; 提供嵌入对象作为其顶级值 字段。 和快照一样,方法接受 `{ target: 'json' }` 以序列化日期和大小 基于JSON的存储.

就乐观货币而言,储存库可包括: `meta.version` 更新条件 将这个版本与修改一起写入。 例如,当描述符有版本 5,a 更新可以要求存储版本为4并设定为5. 无法覆盖一行 被另一个编剧所更改,但每个编剧都遵循相同的版本规则. 零行码 更新是一个冲突,而不是成功的保存.

### 持久性后恢复

`User.restoreEntity(snapshot)` 是静态的,重建一个实体 从持续的快照。 这个 校验 id, 正安全整数版本, 以及针对 secretma 所选择的 chema 的数据 `meta.metaStatus`编辑 `metaStatus` 当数据库查询不返回时,可省略字段; 在这种情况下,按照申报顺序和第一次匹配的状态计划核对数据 假设状态。 如果状态计划重叠, 此命令决定了推断状态, 所以使用 在省略状态时,有特殊要求/歧视性领域。 何时 `metaStatus` 提供, 如果省略,它与可能的国家结合。 A 类 成功的结果 `persistenceStatus: 'unchanged'` 并保存快照的版本; 恢复本身既不能节省,也不能增加.

仅在插入/更新成功后才能调用,最好用数据库返回的行. 恢复实例是下一个编辑周期的基线。 保存第五版后恢复 存储行生成一个不变的版本-5实体;其下一次成功的突变开始版本 6. 如果由于版本冲突而写作失败,保留冲突结果,而不是恢复 尝试的快照仿佛一直存在.

恢复投入不是故意歧视的结合: `data` 使用交叉合并的形状 所有各州。 每个州所需的字段在编译时需要;州特有字段是 可选的普通数据库结果类型仍然可用。 运行时间验证检查完成 明确的计划 `meta.metaStatus`,或推断一个州 并验证该州 省略状态时的计划 。 无论是哪种情况,选定州的所需字段必须是 现相. 这个 `metaStatus` 类型仅限于实体已声明状态;无效的运行时输入 返回时 `INVALID_DATA` 而不是扔东西. 持久性状态没有序列化:由操作决定(`createEntity` 制造 `new`· ; `restoreEntity` 制造 `unchanged`) (中文(简体) ).

抓图包括 `meta.version`,但不会 `persistenceStatus`。 。 。 . `toSnapshot()` 保留 状态特定数据形状,可指定为 `EntityFlatSnapshot`,合并的形状 `restoreEntity()` 接受这个建议。 JSON- 目标快照将日期和大写转换为字符串; 将这些值转换回配置的本地 在将快照传递到 `restoreEntity()`. 支持明确本地与JSON 恢复模式,对日期、时间值和重金进行解码,仍然是计划中的改进.

上面的Schema callback使Zod对象的Schemas适应了工厂. 如果您的状态使用不同的策略或者使用不同的验证库,请为它的标准Schema兼容策略提供等同的回调.

## 出版

该套件被配置为公开npm发布. GitHub Actions在初始版本之后发布 `v*` 标签匹配 `version` 内 `package.json` 被推进。 工作流程运行类型检查、涂料、测试、构建和 `publint` 在使用 npm 出处发布前.

### 一次性设置

1.  确认您的 npm 账户拥有 `@caverar` 范围及范围 `@caverar/ts-entity` 已提供.
    
2.  第一版,发布版本 `1.0.0` 从此取出。 npm 在您可以配置其信任的出版商之前需要软件包存在 :
    
    ```sh
    bun install --frozen-lockfile
    npm login
    npm publish --access public
    ```
    
3.  在 npmjs.com 上打开 `@caverar/ts-entity` → **设置** → **信任的出版商**选择 **GitHub 动作**,并设定:
    
    -   拥有者 : `caverar`
    -   仓库 : `ts-entity`
    -   工作流量 : `publish.yml`
    -   环境:留空
4.  按下一个未发布版本的匹配标签( 例如, 更新软件包到 `1.0.1`,推动 `v1.0.1`) (中文(简体) ). 别推 `v1.0.0` 发布后标记 `1.0.0` 手动;npm不允许发布同版本两次.
    

Npm 令牌或 GitHub 密语在信任的发布启用后不需要发布 。 npm在首次成功发布时验证了新的可信任的出版商配置,因此在创建配置后两天内就推出发行标记.

## 许可证

[仅限GPL-3.0](https://npmcn.com/package/%40caverar/ts-entity/LICENSE)

## 常见问题

### @caverar/ts-entity 是什么？

类型安全域实体具有schema验证,状态过渡,和序列化\.

### 如何安装 @caverar/ts-entity？

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

### @caverar/ts-entity 支持 TypeScript 吗？

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

### @caverar/ts-entity 支持 ESM 还是 CommonJS？

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

### @caverar/ts-entity 需要什么版本的 Node\.js？

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

### @caverar/ts-entity 可以商用吗？

@caverar/ts-entity 使用 GPL-3\.0-only 许可。强 Copyleft：分发包含该代码的软件时，整个作品需以 GPL-3\.0 兼容许可开源，并附带专利与反锁定条款。仅内部使用不触发此义务。以上为概括，不构成法律意见，请以许可原文为准。

### @caverar/ts-entity 的下载量有多少？

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

### @caverar/ts-entity 还在维护吗？

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

