🏖️
ZodのObjectでエラーがあるフィールドだけfallbackしてデフォルトの値にするやり方
個人的に地味に困ったので備忘録。
zodのobjectであるフィールドがinvalidな値が渡された場合、その子だけデフォルトの値で置き換えて、その他の正常な値はそのまま使いたいときの宣言。
TL;DR
各フィールドでcatch
すればいい🚀
const schema = z.object({
str: z.string().default('default string').catch('default string'),
enum: z.enum(['a', 'b', 'c']).default('a').catch('a'),
num: z.coerce.number().default(0).catch(0),
});
間違い🐛
自分がやってしまった懺悔も込めて
default
を使う
const schema = z.object({
str: z.string().default('default string'),
enum: z.enum(['a', 'b', 'c']).default('a'),
num: z.coerce.number().default(0),
});
// error
schema.safeParse({str: 'foo', num: 'a'})
undefined
だった場合default valueを返すのがdefaultの役割。なのでinvalidな値が渡された場合もちろんエラーになる。
catch
する
全体でexport const queryStringParamsSchema = z
.object({
str: z.string(),
enum: z.enum(['a', 'b', 'c']),
num: z.coerce.number(),
})
.catch({
str: 'default string',
enum: 'a',
num: 0,
});
// {str: "default string", enum: "a", num: 0}
schema.safeParse({str: 'foo', num: 'a'})
すべてcatchで指定した値になる。
ちなみにcatch((ctx) => ...)
のctxにinput dataが取れるんだけど、これはparseされていないのでそのまま返すのは危険。
各fieldでcatchするとできた
const schema = z.object({
str: z.string().default('default string').catch('default string'),
enum: z.enum(['a', 'b', 'c']).default('a').catch('a'),
num: z.coerce.number().default(0).catch(0),
});
// {str: "foo", enum: "a", num: 0}
schema.safeParse({str: 'foo', num: 'a'})
ちなみにdefault
はつけてもつけなくても挙動自体は変わらないが、Output
の型を意識して使うなら実態に合わせて宣言する方がいい。(ちょっと冗長的に見えちゃう。。。😅)
Discussion
.catch(defaultValue)
という構文のイメージを持てば、型の方はoptional()
で代用してあげて、うまく折り合いをつけれそうと思いました。demo code.