
【zod】v4で使えるようになったオススメのスキーマ
はじめに
こんにちは、株式会社TOKOSのツキヤです!
2025年の7月に、zodのv4がリリースされましたね🚀
書き方が変わったり、便利なスキーマが追加されたりしました✨
Release notes | Zod
Zod 4 release notes and new features including performance improvements and breaking changes
zod.devそこで、すでにあるが書き方等が変わったスキーマと、新規で便利そうなスキーマ達を紹介しようと思います💪
v3からのマイグレーションガイドも出ているので、一旦バージョンアップだけしたい方はそちらを参考にしてみてください!
Migration guide | Zod
Complete changelog and migration guide for upgrading from Zod 3 to Zod 4
zod.devオススメのスキーマ
まずは、v3以前から有ったスキーマ達です!
z.int()
皆さん、numberがほしいときにフワッとz.number()にしていませんか?
z.number()だと、少数等も含まれてしまいます😨
明確に「整数」が良い時はz.int()を使いましょう!
import { z } from "zod"
const schema = z.int()
schema.parse(1) // 成功!
schema.parse(0.1) // エラー!こちらはv3から有りましたが、z.number().int()と書く必要がありました。
v4からはnumber()の宣言ナシにそのままz.int()と呼べるようになったので覚えておきましょう💪
また、「整数かつ正の数」が良い場合は、z.int().positive()とも書けます!
import { z } from "zod"
const schema = z.int().positive()
schema.parse(1) // 成功!
schema.parse(0.1) // エラー!
schema.parse(-1) // エラー!z.email()
メールアドレスのバリデーションを正規表現で頑張って設定してたりしてないですか??
そんな時に使えるのがz.email()です!
こちらは、一般的なメールアドレスの正規表現をカバーしてくれています✨
z.email()についても、v3からありました。ですが、こちらもz.string().email()のstring()が不要になっています。
また、カスタムもできるようになりました!!
細かく調整したい方はこちらも参照してください。
import { z } from "zod"
/*
* Zodのデフォルトemailバリデーション(Gmail規則)
* colinhacks.com/essays/reasonable-email-regex を参照
*/
z.email()
/*
* ブラウザがinput[type=email]フィールドの検証に使用する正規表現
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email
*/
z.email({ pattern: z.regexes.html5Email })
// RFC 5322に準拠したクラシックなemailregex.comの正規表現
z.email({ pattern: z.regexes.rfc5322Email })
// Unicodeを許可する緩い正規表現(国際化メール対応)
z.email({ pattern: z.regexes.unicodeEmail })他のz.string()系と併用していたスキーマも、同じくstring()が不要になっているので合わせて覚えておきたいです!
extend()
こちらも元からあるもので、スキーマ同士を合成させるような働きでした。
ですが、merge()との違いがよく分かってませんでした🤔
import { z } from "zod"
const humanSchema = z.object({
name: z.string().min(1),
age: z.number().int().positive(),
})
const extendProgramerSchema = humanSchema.extend({
occupation: z.string().min(1),
})
const mergeProgramerSchema = humanSchema.merge(
z.object({
occupation: z.string().min(1),
}),
)
type Human = z.infer<typeof humanSchema>
// => { name: string; age: number }
type Programer = z.infer<typeof extendProgramerSchema>
// => { name: string; age: number; occupation: string } 🤔
type Programer = z.infer<typeof mergeProgramerSchema>
// => { name: string; age: number; occupation: string } 🤔そういった背景もあってか、v4からはmerge()の方が非推奨になりました!
これで自信を持ってextend()を使えるので、皆さん覚えておきましょう🥳
...ただ、スキーマの合成の際のベストプラクティスは「shape + スプレッド構文」になったようです!
スプレッド構文を用いた方法が1番パフォーマンスが良いらしいので、僕は極力こちらを使うようにします!
import { z } from "zod"
const humanSchema = z.object({
name: z.string().min(1),
age: z.number().int().positive(),
})
const occupationSchema = z.object({
occupation: z.string().min(1),
})
const programerSchema = z.object({
...humanSchema.shape,
...occupationSchema.shape,
})
type Programer = z.infer<typeof programerSchema>
// => { name: string; age: number; occupation: string } 🥳refine()
こちらもv3から存在します!
皆さん1回は使ったことがあると思っていて、カスタムのバリデーションを書けるやつですね!
import { z } from "zod"
z.string().refine((val) => val.includes("@")) // 「@」が含まれていないとバリデーションエラー!ただ、v3まではrefine()後にmin()等のスキーマを追加できませんでした🥲
import { z } from "zod"
z.string()
.refine((val) => val.includes("@"))
.min(10) // 型エラー🥲ですが、v4からは可能になりました✨
import { z } from "zod"
z.string()
.refine((val) => val.includes("@"))
.min(10) // 型エラーにならない🥳次からは新しいスキーマの紹介です!!
z.templateLiteral
説明するよりコードを読んだ方が分かりやすいので記載します!
import { z } from "zod"
const email = z.templateLiteral([z.string().min(1), "@", z.string().max(64)])
type Email = z.infer<typeof email>
// => `${string}@${string}`というテンプレートリテラル型になる✨配列の要素をまとめた上でテンプレートリテラル型になってくれる感じです!
パッといい感じの具体例は思い浮かびませんが、覚えておくとどこかしらで使えそうです💪
(上記の例は、z.email()で代用できそうなので...)
z.stringbool()
文字列からいい感じにbooleanに変換したい時ありますよね?
例えば、文字列の"true"をbooleanのtrueにしたい時とかです!
そんな時に使えるのがこちらのstringbool()です!
import { z } from "zod"
const strbool = z.stringbool()
strbool.parse("true") // => true
strbool.parse("1") // => true
strbool.parse("yes") // => true
strbool.parse("on") // => true
strbool.parse("y") // => true
strbool.parse("enabled") // => true
strbool.parse("false") // => false
strbool.parse("0") // => false
strbool.parse("no") // => false
strbool.parse("off") // => false
strbool.parse("n") // => false
strbool.parse("disabled") // => falseこんな感じで、trueっぽい文字列はtrueに、falseっぽい文字列はfalseになります!
ただ、「自分で決めたいぜ!」って人もいると思います。
そんな人のためにも、自分で定義することが可能になっています。
import { z } from "zod"
const strbool = z.stringbool({
truthy: ["yes", "true", "hoge"],
falsy: ["no", "false", "huga"],
})
strbool.parse("yes") // => true
strbool.parse("true") // => true
strbool.parse("hoge") // => true
strbool.parse("no") // => false
strbool.parse("false") // => false
strbool.parse("huga") // => falseおわりに
今回は、v4になったzodの紹介をしました!
破壊的な変更も多く、この他にも便利になったり新しい機能等がいっぱい有るので、ぜひご自身でも確認してみてください!





