Lzh on GitHub

要将 Valibot 从旧版本迁移到 v0.31.0 版本并不复杂。除了新的 pipe 方法外,大多数内容保持不变。以下指南将帮助你自动或手动逐步迁移,并指出重要的差异。

自动升级

我们与 CodemodGrit 合作,通过一个简单的 CLI 命令,可以自动将你的模式升级到新版本。这两个 codemod 相似,你可以任选其一。只需在你的项目目录下运行该命令即可。

我们建议使用像 Git 这样的版本控制系统,这样如果 codemod 搞砸了什么,你可以还原更改。

# Codemod
npx codemod valibot/migrate-to-v0.31.0

# Grit
npx @getgrit/cli apply github.com/fabian-hiller/valibot#migrate_to_v0_31_0

如果你在使用提供的 codemod 时遇到任何问题或意外行为,请创建一个 issue

重构代码

如上所述,最大的区别之一是新的 pipe 方法。以前,你将管道作为数组传递给模式函数。现在,你将模式和各种操作传递给新的 pipe 方法来扩展模式。

// 改为
const Schema = v.pipe(v.string(), v.email());
// 而不是
const Schema = v.string([v.email()]);

更改名称

大多数名称与以前相同。但是,也有一些例外。下表列出了所有已更改的名称。

v0.30.0v0.31.0
anyAsyncany
anyBaseSchemaGenericSchema
bigintAsyncbigint
blobAsyncblob
booleanAsyncboolean
customcheck
customAsynccheckAsync
coercepipe, unknowntransform
dateAsyncdate
enumAsyncenum
_InputInferInput
instanceAsyncinstance
literalAsyncliteral
nanAsyncnan
neverAsyncnever
nullAsyncnull
_numberAsyncnumber
OutputInferOutput
picklistAsyncpicklist
SchemaConfigConfig
specialcustom
specialAsynccustomAsync
SchemaConfigConfig
stringAsyncstring
symbolAsyncsymbol
undefinedAsyncundefined
_unknownAsyncunknown
toCustomtransform
toTrimmedtrim
toTrimmedEndtrimEnd
toTrimmedStarttrimStart
voidAsyncvoid
_

特殊情况

更复杂的模式可能需要更多的重构。本节提供了如何迁移特定函数的更多详细信息。

对象和元组

以前,你可以将 rest 参数传递给 objecttuple 模式,以定义未知条目和项的行为。我们已删除 rest 参数以简化实现,并在不需要此功能时减小打包体积。如果你确实需要此功能,现在有了新的 objectWithResttupleWithRest 模式。

// 改为
const ObjectSchema = v.objectWithRest({ key: v.string() }, v.null_());
const TupleSchema = v.tupleWithRest([v.string()], v.null_());
// 而不是
const ObjectSchema = v.object({ key: v.string() }, v.null_());
const TupleSchema = v.tuple([v.string()], v.null_());

为了进一步改善开发者体验,我们还添加了 looseObjectlooseTuplestrictObjectstrictTuple 模式。这些模式允许或禁止未知条目或项。

// 改为
const LooseObjectSchema = v.looseObject({ key: v.string() });
const LooseTupleSchema = v.looseTuple([v.string()]);
const StrictObjectSchema = v.strictObject({ key: v.string() });
const StrictTupleSchema = v.strictTuple([v.string()]);
// 而不是
const LooseObjectSchema = v.object({ key: v.string() }, v.unknown());
const LooseTupleSchema = v.tuple([v.string()], v.unknown());
const StrictObjectSchema = v.object({ key: v.string() }, v.never());
const StrictTupleSchema = v.tuple([v.string()], v.never());

对象合并

由于现在有 4 种不同的对象模式,我们无法再提供一个适用于所有情况的简单 merge 函数,因为我们不知道你想要将其他对象合并到哪种模式中。但是,有一个简单的变通方法,可以提供类似的开发者体验。

const ObjectSchema1 = v.object({ foo: v.string() });
const ObjectSchema2 = v.object({ bar: v.number() });

// 改为
const MergedObject = v.object({
  ...ObjectSchema1.entries,
  ...ObjectSchema2.entries,
});
// 而不是
const MergedObject = v.merge([ObjectSchema1, ObjectSchema2]);

brandtransform

以前,brandtransform 是可以包裹模式以修改它的方法。有了我们新的 pipe 方法,这不再是必需的。相反,brandtransform 现在是转换操作,可以直接放在管道中,从而获得更好的可读性,特别是对于复杂的模式。

// 改为
const BrandedSchema = v.pipe(v.string(), v.brand('foo'));
const TransformedSchema = v.pipe(
  v.string(),
  v.transform((input) => input.length)
);
// 而不是
const BrandedSchema = v.brand(v.string(), 'foo');
const TransformedSchema = v.transform(v.string(), (input) => input.length);

coerce 方法

coerce 方法已被移除,因为我们认为它是一个不安全的 API。在大多数情况下,你不想将未知输入强制转换为特定数据类型。相反,你希望将特定数据类型转换为另一种特定数据类型。例如,将字符串或数字转换为日期。要明确定义输入类型,我们建议使用新的 pipe 方法和 transform 操作来实现相同的功能。

// 改为
const DateSchema = v.pipe(
  v.union([v.string(), v.number()]),
  v.transform((input) => new Date(input))
);
// 而不是
const DateSchema = v.coerce(v.date(), (input) => new Date(input));

flatten 问题

以前,flatten 函数接受一个 ValiError 或一个问题数组。我们简化了实现,只允许传递一个问题数组。

// 改为
const flatErrors = v.flatten(error.issues);
// 而不是
const flatErrors = v.flatten(error);