name: 静态工作区-api description: 静态工作区API模式,用于defineTable、defineKv、版本化和迁移。在定义工作区模式、为现有表格/KV存储添加版本或编写迁移函数时使用。 metadata: author: epicenter version: ‘2.0’
静态工作区API
用于表格和KV存储的类型安全模式定义,支持版本化迁移。
何时应用此技能
- 使用
defineTable()或defineKv()定义新表格或KV存储 - 为现有定义添加新版本
- 编写迁移函数
- 从简写模式转换为构建器模式
表格
简写模式(单版本)
当表格只有一个版本时使用:
import { defineTable } from 'epicenter/static';
import { type } from 'arktype';
const users = defineTable(type({ id: 'string', email: 'string', _v: '1' }));
每个表格模式必须包含_v和数字字面量。类型系统强制执行此要求 — 将不包含_v的模式传递给defineTable()会导致编译错误。
构建器模式(多版本)
当您需要随时间演进模式时使用:
const posts = defineTable()
.version(type({ id: 'string', title: 'string', _v: '1' }))
.version(type({ id: 'string', title: 'string', views: 'number', _v: '2' }))
.migrate((row) => {
switch (row._v) {
case 1:
return { ...row, views: 0, _v: 2 };
case 2:
return row;
}
});
KV存储
KV存储灵活 — _v是可选的。两种模式都有效:
不带_v(字段存在性)
import { defineKv } from 'epicenter/static';
const sidebar = defineKv(type({ collapsed: 'boolean', width: 'number' }));
// 多版本,使用字段存在性
const theme = defineKv()
.version(type({ mode: "'light' | 'dark'" }))
.version(type({ mode: "'light' | 'dark' | 'system'", fontSize: 'number' }))
.migrate((v) => {
if (!('fontSize' in v)) return { ...v, fontSize: 14 };
return v;
});
带_v(显式判别)
const theme = defineKv()
.version(type({ mode: "'light' | 'dark'", _v: '1' }))
.version(
type({ mode: "'light' | 'dark' | 'system'", fontSize: 'number', _v: '2' }),
)
.migrate((v) => {
switch (v._v) {
case 1:
return { ...v, fontSize: 14, _v: 2 };
case 2:
return v;
}
});
_v约定
_v是一个数字判别字段('1'在arktype中表示字面数字1)- 对表格必填 — 通过类型级别
CombinedStandardSchema<{ id: string; _v: number }>强制执行 - 对KV存储可选 — KV保持完全灵活性
- 在arktype模式中:
_v: '1'、_v: '2'、_v: '3'(数字字面量) - 在迁移返回中:
_v: 2(TypeScript自动缩小类型,as const不必要) - 约定:
_v放在对象的最后({ id, ...fields, _v: '1' })
迁移函数规则
- 输入类型是所有版本输出的并集
- 返回类型是最新版本输出
- 使用
switch (row._v)进行判别(表格总是有_v) - 最后一个case直接返回
row(已是最新版本) - 始终直接迁移到最新版本(不逐步通过每个版本)
反模式
逐步迁移(v1 -> v2 -> v3)
// 错误:通过每个版本链式迁移
.migrate((row) => {
let current = row;
if (current._v === 1) current = { ...current, views: 0, _v: 2 };
if (current._v === 2) current = { ...current, tags: [], _v: 3 };
return current;
})
// 正确:直接迁移到最新版本
.migrate((row) => {
switch (row._v) {
case 1: return { ...row, views: 0, tags: [], _v: 3 };
case 2: return { ...row, tags: [], _v: 3 };
case 3: return row;
}
})
注意:as const不必要
TypeScript基于返回类型约束上下文性地缩小_v: 2到字面类型。这两种都有效:
return { ...row, views: 0, _v: 2 }; // 有效 — 上下文缩小
return { ...row, views: 0, _v: 2 as const }; // 也有效 — 冗余
参考
packages/epicenter/src/static/define-table.tspackages/epicenter/src/static/define-kv.tspackages/epicenter/src/static/index.tspackages/epicenter/src/static/create-tables.tspackages/epicenter/src/static/create-kv.ts