DrizzleORM类型branding指南Skill drizzle-orm

这个技能提供了Drizzle ORM中类型branding和自定义类型的最佳实践指南,包括使用$type<T>()避免运行时开销和保持数据序列化以提高系统效率。关键词:Drizzle ORM, TypeScript, 类型branding, 自定义类型, 数据库开发, 后端开发, 性能优化。

后端开发 0 次安装 0 次浏览 更新于 3/20/2026

name: drizzle-orm description: Drizzle ORM 的模式用于类型branding和自定义类型。在使用Drizzle列定义、branded类型或自定义类型转换时使用。

Drizzle ORM 指南

使用 $type<T>() 用于Branded Strings,而不是customType

当你需要一个带有branded TypeScript类型但无需实际数据转换的列时,使用 $type<T>() 而不是 customType

规则

如果 toDriverfromDriver 是恒等函数 (x) => x,则使用 $type<T>()

为什么

即使使用恒等函数,customType 仍然在每个行上调用 mapFromDriverValue

// drizzle-orm/src/utils.ts - 对每个列的每个行运行
const rawValue = row[columnIndex]!;
const value = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);

查询1000行,每行有3个日期列 = 3000个函数调用无所事事。

坏的模式

// 运行时开销对于恒等函数
customType<{ data: DateTimeString; driverParam: DateTimeString }>({
	dataType: () => 'text',
	toDriver: (value) => value, // 在每次写入时调用
	fromDriver: (value) => value, // 在每次读取时调用
});

好的模式

// 零运行时开销 - 纯类型断言
text().$type<DateTimeString>();

$type<T>() 是仅编译时的类型覆盖:

// drizzle-orm/src/column-builder.ts
$type<TType>(): $Type<this, TType> {
  return this as $Type<this, TType>;
}

何时使用customType

仅当数据在应用程序和数据库之间真正转换时:

// JSON: 对象 ↔ 字符串 - 实际转换
customType<{ data: UserPrefs; driverParam: string }>({
	toDriver: (value) => JSON.stringify(value),
	fromDriver: (value) => JSON.parse(value),
});

保持数据在中间表示中

优先保持数据序列化(字符串)通过系统,仅在边缘(UI组件)解析。

原则:如果数据以序列化形式进入并以序列化形式离开,保持它在中间序列化。在真正需要丰富表示的边缘解析。

示例:DateTimeString

而不是在数据库层将 DateTimeString 解析为 Temporal.ZonedDateTime

// 坏:在每次读取时解析,在API边界重新序列化
customType<{ data: Temporal.ZonedDateTime; driverParam: string }>({
	fromDriver: (value) => fromDateTimeString(value),
});

保持它为字符串,直到UI真正需要它:

// 好:字符串保持字符串,仅在日期选择器组件解析
text().$type<DateTimeString>();

// 在UI组件中:
const temporal = fromDateTimeString(row.createdAt);
// 编辑后:
const updated = toDateTimeString(temporal);