迁移到 v0.31.0
要将 Valibot 从旧版本迁移到 v0.31.0 版本并不复杂。除了新的 pipe 方法外,大多数内容保持不变。以下指南将帮助你自动或手动逐步迁移,并指出重要的差异。
自动升级
我们与 Codemod 和 Grit 合作,通过一个简单的 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.0 | v0.31.0 |
|---|---|
anyAsync | any |
anyBaseSchema | GenericSchema |
bigintAsync | bigint |
blobAsync | blob |
booleanAsync | boolean |
custom | check |
customAsync | checkAsync |
coerce | pipe, unknown 和 transform |
dateAsync | date |
enumAsync | enum |
_Input | InferInput |
instanceAsync | instance |
literalAsync | literal |
nanAsync | nan |
neverAsync | never |
nullAsync | null |
_numberAsync | number |
Output | InferOutput |
picklistAsync | picklist |
SchemaConfig | Config |
special | custom |
specialAsync | customAsync |
SchemaConfig | Config |
stringAsync | string |
symbolAsync | symbol |
undefinedAsync | undefined |
_unknownAsync | unknown |
toCustom | transform |
toTrimmed | trim |
toTrimmedEnd | trimEnd |
toTrimmedStart | trimStart |
voidAsync | void |
_ |
特殊情况
更复杂的模式可能需要更多的重构。本节提供了如何迁移特定函数的更多详细信息。
对象和元组
以前,你可以将 rest 参数传递给 object 和 tuple 模式,以定义未知条目和项的行为。我们已删除 rest 参数以简化实现,并在不需要此功能时减小打包体积。如果你确实需要此功能,现在有了新的 objectWithRest 和 tupleWithRest 模式。
// 改为
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_());
为了进一步改善开发者体验,我们还添加了 looseObject、looseTuple、strictObject 和 strictTuple 模式。这些模式允许或禁止未知条目或项。
// 改为
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]);
brand 和 transform
以前,brand 和 transform 是可以包裹模式以修改它的方法。有了我们新的 pipe 方法,这不再是必需的。相反,brand 和 transform 现在是转换操作,可以直接放在管道中,从而获得更好的可读性,特别是对于复杂的模式。
// 改为
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);