@caverar/ts-entity

中文文档
1.4.0发布于 2026/11/06GPL-3.0-onlyTypeScriptES Module零依赖近 30 天下载 2617

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

中文使用文档
文档目录11 节
  1. 安装
  2. 快开始
  3. 选择输出
  4. 持久性和乐观的货币
  5. 创建新实体
  6. 改变一个实体
  7. 描述持久性变化
  8. 持久性后恢复
  9. 出版
  10. 一次性设置
  11. 许可证

@caverar/ts-实体

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

安装

npm install @caverar/ts-entity zod

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

快开始

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: '[email protected]', 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存储的硬币 见 选择输出 何时使用 相对于其他系列化方法.

选择输出

实体揭露出三个集团的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 的密钥, 用于大小写输入
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版. 再来 该周期的突变仍为第五版. 对于乐观的更新,请使用上一个版本作为 比较条件和实体的版本作为写入的值:

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 在您可以配置其信任的出版商之前需要软件包存在 :

    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

版本与发布记录

@caverar/ts-entity 共发布 16 个版本,首次发布于 2026/10/20;过去 12 个月发布了 16 个版本。

版本发布日期距今
1.4.0latest2026/11/063 天前
1.3.02026/11/044 天前
1.2.02026/11/045 天前
1.1.12026/11/035 天前
1.1.02026/11/035 天前
1.0.92026/11/036 天前

关于 @caverar/ts-entity 的常见问题

@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 和提交记录判断。