https://zod.dev
Validasi Skema TypeScript-First dengan inferensi tipe statis
Dokumen ini telah diterjemahkan ke dalam bahasa Mandarin.
npm
(Node/Bun)deno.land/x
(Deno).shape
.keyof
.extend
.merge
.pick/.omit
.partial
.deepPartial
.required
.passthrough
.strict
.strip
.catchall
.element
.nonempty
.min/.max/.length
.parse
.parseAsync
.safeParse
.safeParseAsync
.refine
.superRefine
.transform
.default
.describe
.catch
.optional
.nullable
.nullish
.array
.promise
.or
.and
.brand
.readonly
.pipe
.pipe()
to fix common issues with z.coerce
. Zod adalah Perpustakaan Deklarasi dan Validasi Skema First-TypeScript. Saya menggunakan istilah "skema" untuk secara luas merujuk ke tipe data apa pun, dari string
sederhana ke objek bersarang yang kompleks.
Zod dirancang untuk menjadi ramah-pengembang. Tujuannya adalah untuk menghilangkan deklarasi tipe duplikasi. Dengan Zod, Anda mendeklarasikan validator sekali dan Zod akan secara otomatis menyimpulkan tipe TypeScript statis. Mudah untuk menyusun tipe yang lebih sederhana ke dalam struktur data yang kompleks.
Beberapa aspek hebat lainnya:
.optional()
) mengembalikan contoh baruSponsorship at any level is appreciated and encouraged. Jika Anda membangun produk berbayar menggunakan ZOD, pertimbangkan salah satu tingkatan perusahaan.
Platform manajemen pengguna paling komprehensif
Clerk.com
|
|
|
|
|
Propelauth | Cerbo | Skalar | Pemicu.dev |
Transloadit | Infisical | Menggebuk | Cryptojobslist |
Polos. | Inngest | StoryBlok | Mux |
Brandon Bayer | Jiří Brabec | Alex Johansson | Sistem Fungible |
Bisa beradaptasi | Dompet Avana | Jason Lengstorf | Global Illumination, Inc. |
Masterborn | Ryan Palmer | Michael Sweeney | Nextbase |
Remosi | Connor Sinnott | Mohammad-Ali A'râbi | Supatool |
Ada semakin banyak alat yang dibangun di atas atau mendukung Zod secara asli! Jika Anda telah membangun alat atau perpustakaan di atas Zod, beri tahu saya di Twitter atau memulai diskusi. Saya akan menambahkannya di bawah dan tweetnya.
tRPC
: Bangun API TypeSafe end-to-end tanpa GraphQL.@anatine/zod-nestjs
: Metode pembantu untuk menggunakan Zod dalam proyek NestJS.zod-endpoints
: Kontrak-pertama yang diketikkan titik akhir dengan Zod. Openapi kompatibel.zhttp
: An OpenAPI compatible, strictly typed http library with Zod input and response validation.domain-functions
: Decouple logika bisnis Anda dari kerangka kerja Anda menggunakan fungsi komposable. Dengan inferensi tipe kelas satu dari ujung ke ujung yang ditenagai oleh skema Zod.@zodios/core
: Klien API TypeScript dengan runtime dan kompilasi waktu validasi yang didukung oleh Axios dan Zod.express-zod-api
: Build Express-based APIs with I/O schema validation and custom middlewares.tapiduck
: Type-end JSAFE JSON API dengan Zod dan Express; Agak seperti TRPC, tetapi lebih sederhana.koa-zod-router
: Buat rute TypeSafe di KOA dengan validasi I/O menggunakan ZOD.zod-sockets
: Zod-bertenaga socket.io microframework dengan validasi I/O dan spesifikasi asyncapi bawaan react-hook-form
: Resolver Zod pihak pertama untuk bentuk react hook.zod-validation-error
: Hasilkan pesan kesalahan yang ramah pengguna dari ZodError
s.zod-formik-adapter
: Adaptor Formik yang dipelihara oleh komunitas untuk Zod.react-zorm
: Generasi dan validasi <form>
dan validasi untuk React menggunakan ZOD.zodix
: Utilitas Zod untuk Formdata dan UrlSearchParams di Remix Loader dan Tindakan.conform
: Perpustakaan Validasi Formulir TypeSafe untuk peningkatan progresif formulir HTML. Bekerja dengan Remix dan Next.js.remix-params-helper
: Sederhanakan integrasi ZOD dengan URLSearchParams dan FormData standar untuk aplikasi remix.formik-validator-zod
: Perpustakaan Validator yang sesuai dengan Formik yang menyederhanakan menggunakan Zod dengan Formik.zod-i18n-map
: Berguna untuk menerjemahkan pesan kesalahan ZOD.@modular-forms/solid
: Perpustakaan Bentuk Modular untuk SolidJs yang mendukung ZOD untuk validasi.houseform
: Perpustakaan Bentuk Bereaksi yang menggunakan ZOD untuk validasi.sveltekit-superforms
: Perpustakaan formulir supercharged untuk Sveltekit dengan validasi ZOD.mobx-zod-form
: pembangun formulir data-pertama berdasarkan MOBX & ZOD.@vee-validate/zod
: Bentuk Perpustakaan untuk Vue.js dengan validasi skema ZOD.zod-form-renderer
: Auto-infer membentuk bidang dari skema ZOD dan membuatnya dengan react-hook-form dengan keamanan tipe E2E. zod-to-ts
: Generate TypeScript definitions from Zod schemas.zod-to-json-schema
: Convert your Zod schemas into JSON Schemas.@anatine/zod-openapi
: Mengubah skema ZOD menjadi SchemaObject
OpenAPI v3.x.zod-fast-check
: menghasilkan arbitrari fast-check
dari skema zod.zod-dto
: Hasilkan DTOS Nest.js dari skema ZOD.fastify-type-provider-zod
: Buat penyedia jenis pengisian ulang dari skema ZOD.zod-to-openapi
: Hasilkan OpenAPI penuh (Swagger) Docs dari Zod, termasuk skema, titik akhir & parameter.nestjs-graphql-zod
: Menghasilkan kelas model graphql NestJS dari skema zod. Menyediakan dekorator metode graphql yang bekerja dengan skema zod.zod-openapi
: Buat dokumentasi OpenAPI v3.x lengkap dari skema Zod.fastify-zod-openapi
: Memperbaiki Penyedia Jenis, Validasi, Serialisasi dan Dukungan @Pengisian/Swagger untuk Skema Zod.typeschema
: Adaptor universal untuk validasi skema.zodex
: (DE) serialisasi untuk skema zod ts-to-zod
: Konversi definisi naskah menjadi skema zod.@runtyping/zod
: menghasilkan zod dari statis tipe & skema json.json-schema-to-zod
: Konversi skema JSON Anda menjadi skema Zod. Demo langsung.json-to-zod
: Konversi objek JSON menjadi skema Zod. Live demo.graphql-codegen-typescript-validation-schema
: Plugin Generator Kode GraphQL untuk menghasilkan skema validasi formulir dari skema GraphQL Anda.zod-prisma
: Hasilkan skema Zod dari skema prisma Anda.Supervillain
: Generate Zod schemas from your Go structs.prisma-zod-generator
: Emit skema Zod dari skema prisma Anda.drizzle-zod
: Emit skema zod dari skema gerimis Anda.prisma-trpc-generator
: memancarkan router TRPC yang diimplementasikan sepenuhnya dan skema validasinya menggunakan ZOD.zod-prisma-types
Membuat tipe Zod dari model prisma Anda.quicktype
: Konversi objek JSON dan skema JSON menjadi skema Zod.@sanity-typed/zod
: Hasilkan skema zod dari skema kewarasan.java-to-zod
: Konversi Pojos ke Skema ZodOrval
: menghasilkan skema zod dari skema openapiKubb
: Hasilkan skema SDK dan ZOD dari skema OpenAPI Anda @anatine/zod-mock
: Hasilkan data tiruan dari skema ZOD. Powered by faker.js.zod-mocking
: Hasilkan data tiruan dari skema zod Anda.zod-fixture
: Gunakan skema zod Anda untuk mengotomatisasi generasi perlengkapan uji yang tidak relevan dengan cara deterministik.zocker
: Hasilkan data tiruan yang masuk akal dari skema Anda.zodock
menghasilkan data tiruan berdasarkan skema ZOD.zod-schema-faker
menghasilkan data tiruan dari skema Zod. Didukung oleh @faker-js/faker dan randexp.js freerstore
: Pengoptimal Biaya Firestore.slonik
: klien Node.js Postgres dengan integrasi Zod yang kuat.schemql
: Meningkatkan alur kerja SQL Anda dengan menggabungkan SQL mentah dengan keamanan jenis dan validasi skema yang ditargetkan.soly
: Buat aplikasi CLI dengan Zod.pastel
: Buat aplikasi CLI dengan React, Zod, dan Ink.zod-xlsx
: Validator sumber daya berbasis XLSX menggunakan skema ZOD.znv
: Parsing dan validasi lingkungan tipe-aman untuk node.js dengan skema zod.zod-config
: Muat konfigurasi di berbagai sumber dengan adaptor fleksibel, memastikan jenis keamanan dengan Zod.unplugin-environment
: Plugin untuk memuat variabel lingkungan dengan aman dengan validasi skema, sederhana dengan modul virtual, jenis-aman dengan intelisense, dan dx yang lebih baik? Didukung oleh Zod. zod_utilz
: Kerangka kerja agnostik untuk zod.zod-playground
: Alat untuk belajar dan menguji fungsionalitas validasi skema ZOD. Link.zod-sandbox
: Lingkungan Terkendali untuk Menguji Skema Zod. Demo langsung.zod-dev
: Secara kondisional menonaktifkan penguraian runtime zod dalam produksi.zod-accelerator
: Mempercepat throughput Zod hingga ~ 100x. TypeScript 4.5+!
Anda harus mengaktifkan mode strict
di tsconfig.json
Anda. Ini adalah praktik terbaik untuk semua proyek naskah.
// tsconfig.json
{
// ...
"compilerOptions" : {
// ...
"strict" : true
}
}
npm
(Node/Bun) npm install zod # npm
yarn add zod # yarn
bun add zod # bun
pnpm add zod # pnpm
Zod juga menerbitkan versi Canary di setiap komit. To install the canary:
npm install zod@canary # npm
yarn add zod@canary # yarn
bun add zod@canary # bun
pnpm add zod@canary # pnpm
deno.land/x
(Deno)Tidak seperti Node, Deno mengandalkan impor URL langsung alih -alih manajer paket seperti NPM. Zod is available on deno.land/x. Versi terbaru dapat diimpor seperti itu:
import { z } from "https://deno.land/x/zod/mod.ts" ;
Anda juga dapat menentukan versi tertentu:
import { z } from "https://deno.land/x/[email protected]/mod.ts" ;
Sisa readme ini mengasumsikan Anda menggunakan NPM dan mengimpor langsung dari paket
"zod"
.
Membuat skema string sederhana
import { z } from "zod" ;
// creating a schema for strings
const mySchema = z . string ( ) ;
// parsing
mySchema . parse ( "tuna" ) ; // => "tuna"
mySchema . parse ( 12 ) ; // => throws ZodError
// "safe" parsing (doesn't throw error if validation fails)
mySchema . safeParse ( "tuna" ) ; // => { success: true; data: "tuna" }
mySchema . safeParse ( 12 ) ; // => { success: false; error: ZodError }
Membuat skema objek
import { z } from "zod" ;
const User = z . object ( {
username : z . string ( ) ,
} ) ;
User . parse ( { username : "Ludwig" } ) ;
// extract the inferred type
type User = z . infer < typeof User > ;
// { username: string }
import { z } from "zod" ;
// primitive values
z . string ( ) ;
z . number ( ) ;
z . bigint ( ) ;
z . boolean ( ) ;
z . date ( ) ;
z . symbol ( ) ;
// empty types
z . undefined ( ) ;
z . null ( ) ;
z . void ( ) ; // accepts undefined
// catch-all types
// allows any value
z . any ( ) ;
z . unknown ( ) ;
// never type
// allows no values
z . never ( ) ;
Zod sekarang memberikan cara yang lebih nyaman untuk memaksa nilai primitif.
const schema = z . coerce . string ( ) ;
schema . parse ( "tuna" ) ; // => "tuna"
schema . parse ( 12 ) ; // => "12"
Selama langkah parsing, input dilewatkan melalui fungsi String()
, yang merupakan javascript built-in untuk memaksa data ke dalam string.
schema . parse ( 12 ) ; // => "12"
schema . parse ( true ) ; // => "true"
schema . parse ( undefined ) ; // => "undefined"
schema . parse ( null ) ; // => "null"
The returned schema is a normal ZodString
instance so you can use all string methods.
z . coerce . string ( ) . email ( ) . min ( 5 ) ;
Bagaimana paksaan bekerja
Semua tipe primitif mendukung paksaan. Zod memaksa semua input menggunakan konstruktor bawaan: String(input)
, Number(input)
, new Date(input)
, dll.
z . coerce . string ( ) ; // String(input)
z . coerce . number ( ) ; // Number(input)
z . coerce . boolean ( ) ; // Boolean(input)
z . coerce . bigint ( ) ; // BigInt(input)
z . coerce . date ( ) ; // new Date(input)
Catatan - Paksaan Boolean dengan z.coerce.boolean()
mungkin tidak berfungsi seperti yang Anda harapkan. Nilai kebenaran apa pun dipaksa untuk true
, dan nilai apa pun yang dipaksa dipaksa untuk false
.
const schema = z . coerce . boolean ( ) ; // Boolean(input)
schema . parse ( "tuna" ) ; // => true
schema . parse ( "true" ) ; // => true
schema . parse ( "false" ) ; // => true
schema . parse ( 1 ) ; // => true
schema . parse ( [ ] ) ; // => true
schema . parse ( 0 ) ; // => false
schema . parse ( "" ) ; // => false
schema . parse ( undefined ) ; // => false
schema . parse ( null ) ; // => false
Untuk kontrol lebih lanjut atas logika paksaan, pertimbangkan untuk menggunakan z.preprocess
atau z.pipe()
.
Skema literal mewakili jenis literal, seperti "hello world"
atau 5
.
const tuna = z . literal ( "tuna" ) ;
const twelve = z . literal ( 12 ) ;
const twobig = z . literal ( 2n ) ; // bigint literal
const tru = z . literal ( true ) ;
const terrificSymbol = Symbol ( "terrific" ) ;
const terrific = z . literal ( terrificSymbol ) ;
// retrieve literal value
tuna . value ; // "tuna"
Saat ini tidak ada dukungan untuk literal tanggal di Zod. Jika Anda memiliki kasus penggunaan untuk fitur ini, silakan ajukan masalah.
Zod menyertakan beberapa validasi spesifik string.
// validations
z . string ( ) . max ( 5 ) ;
z . string ( ) . min ( 5 ) ;
z . string ( ) . length ( 5 ) ;
z . string ( ) . email ( ) ;
z . string ( ) . url ( ) ;
z . string ( ) . emoji ( ) ;
z . string ( ) . uuid ( ) ;
z . string ( ) . nanoid ( ) ;
z . string ( ) . cuid ( ) ;
z . string ( ) . cuid2 ( ) ;
z . string ( ) . ulid ( ) ;
z . string ( ) . regex ( regex ) ;
z . string ( ) . includes ( string ) ;
z . string ( ) . startsWith ( string ) ;
z . string ( ) . endsWith ( string ) ;
z . string ( ) . datetime ( ) ; // ISO 8601; by default only `Z` timezone allowed
z . string ( ) . ip ( ) ; // defaults to allow both IPv4 and IPv6
// transforms
z . string ( ) . trim ( ) ; // trim whitespace
z . string ( ) . toLowerCase ( ) ; // toLowerCase
z . string ( ) . toUpperCase ( ) ; // toUpperCase
// added in Zod 3.23
z . string ( ) . date ( ) ; // ISO date format (YYYY-MM-DD)
z . string ( ) . time ( ) ; // ISO time format (HH:mm:ss[.SSSSSS])
z . string ( ) . duration ( ) ; // ISO 8601 duration
z . string ( ) . base64 ( ) ;
Lihat Validator.js untuk sekelompok fungsi validasi string bermanfaat lainnya yang dapat digunakan bersama dengan penyempurnaan.
Anda dapat menyesuaikan beberapa pesan kesalahan umum saat membuat skema string.
const name = z . string ( {
required_error : "Name is required" ,
invalid_type_error : "Name must be a string" ,
} ) ;
Saat menggunakan metode validasi, Anda dapat lulus dalam argumen tambahan untuk memberikan pesan kesalahan khusus.
z . string ( ) . min ( 5 , { message : "Must be 5 or more characters long" } ) ;
z . string ( ) . max ( 5 , { message : "Must be 5 or fewer characters long" } ) ;
z . string ( ) . length ( 5 , { message : "Must be exactly 5 characters long" } ) ;
z . string ( ) . email ( { message : "Invalid email address" } ) ;
z . string ( ) . url ( { message : "Invalid url" } ) ;
z . string ( ) . emoji ( { message : "Contains non-emoji characters" } ) ;
z . string ( ) . uuid ( { message : "Invalid UUID" } ) ;
z . string ( ) . includes ( "tuna" , { message : "Must include tuna" } ) ;
z . string ( ) . startsWith ( "https://" , { message : "Must provide secure URL" } ) ;
z . string ( ) . endsWith ( ".com" , { message : "Only .com domains allowed" } ) ;
z . string ( ) . datetime ( { message : "Invalid datetime string! Must be UTC." } ) ;
z . string ( ) . date ( { message : "Invalid date string!" } ) ;
z . string ( ) . time ( { message : "Invalid time string!" } ) ;
z . string ( ) . ip ( { message : "Invalid IP address" } ) ;
Seperti yang mungkin Anda perhatikan, Zod String menyertakan beberapa validasi terkait tanggal/waktu. Validasi ini berbasis ekspresi reguler, sehingga tidak seketat perpustakaan tanggal/waktu penuh. Namun, mereka sangat nyaman untuk memvalidasi input pengguna.
Metode z.string().datetime()
menegakkan ISO 8601; Default tidak ada offset zona waktu dan presisi desimal sub-detik yang sewenang-wenang.
const datetime = z . string ( ) . datetime ( ) ;
datetime . parse ( "2020-01-01T00:00:00Z" ) ; // pass
datetime . parse ( "2020-01-01T00:00:00.123Z" ) ; // pass
datetime . parse ( "2020-01-01T00:00:00.123456Z" ) ; // pass (arbitrary precision)
datetime . parse ( "2020-01-01T00:00:00+02:00" ) ; // fail (no offsets allowed)
Offset TimeZone dapat diizinkan dengan mengatur opsi offset
ke true
.
const datetime = z . string ( ) . datetime ( { offset : true } ) ;
datetime . parse ( "2020-01-01T00:00:00+02:00" ) ; // pass
datetime . parse ( "2020-01-01T00:00:00.123+02:00" ) ; // pass (millis optional)
datetime . parse ( "2020-01-01T00:00:00.123+0200" ) ; // pass (millis optional)
datetime . parse ( "2020-01-01T00:00:00.123+02" ) ; // pass (only offset hours)
datetime . parse ( "2020-01-01T00:00:00Z" ) ; // pass (Z still supported)
Anda juga dapat membatasi precision
yang diijinkan. Secara default, presisi sub-detik yang sewenang-wenang didukung (tetapi opsional).
const datetime = z . string ( ) . datetime ( { precision : 3 } ) ;
datetime . parse ( "2020-01-01T00:00:00.123Z" ) ; // pass
datetime . parse ( "2020-01-01T00:00:00Z" ) ; // fail
datetime . parse ( "2020-01-01T00:00:00.123456Z" ) ; // fail
Ditambahkan dalam Zod 3.23
Metode z.string().date()
memvalidasi string dalam format YYYY-MM-DD
.
const date = z . string ( ) . date ( ) ;
date . parse ( "2020-01-01" ) ; // pass
date . parse ( "2020-1-1" ) ; // fail
date . parse ( "2020-01-32" ) ; // fail
Ditambahkan dalam Zod 3.23
Metode z.string().time()
memvalidasi string dalam format HH:MM:SS[.s+]
. Yang kedua dapat mencakup ketepatan desimal sewenang -wenang. Itu tidak mengizinkan offset zona waktu dalam bentuk apa pun.
const time = z . string ( ) . time ( ) ;
time . parse ( "00:00:00" ) ; // pass
time . parse ( "09:52:31" ) ; // pass
time . parse ( "23:59:59.9999999" ) ; // pass (arbitrary precision)
time . parse ( "00:00:00.123Z" ) ; // fail (no `Z` allowed)
time . parse ( "00:00:00.123+02:00" ) ; // fail (no offsets allowed)
Anda dapat mengatur opsi precision
untuk membatasi presisi desimal yang diijinkan.
const time = z . string ( ) . time ( { precision : 3 } ) ;
time . parse ( "00:00:00.123" ) ; // pass
time . parse ( "00:00:00.123456" ) ; // fail
time . parse ( "00:00:00" ) ; // fail
The z.string().ip()
method by default validate IPv4 and IPv6.
const ip = z . string ( ) . ip ( ) ;
ip . parse ( "192.168.1.1" ) ; // pass
ip . parse ( "84d5:51a0:9114:1855:4cfa:f2d7:1f12:7003" ) ; // pass
ip . parse ( "84d5:51a0:9114:1855:4cfa:f2d7:1f12:192.168.1.1" ) ; // pass
ip . parse ( "256.1.1.1" ) ; // fail
ip . parse ( "84d5:51a0:9114:gggg:4cfa:f2d7:1f12:7003" ) ; // fail
Anda juga dapat mengatur version
IP.
const ipv4 = z . string ( ) . ip ( { version : "v4" } ) ;
ipv4 . parse ( "84d5:51a0:9114:1855:4cfa:f2d7:1f12:7003" ) ; // fail
const ipv6 = z . string ( ) . ip ( { version : "v6" } ) ;
ipv6 . parse ( "192.168.1.1" ) ; // fail
Anda dapat menyesuaikan pesan kesalahan tertentu saat membuat skema angka.
const age = z . number ( {
required_error : "Age is required" ,
invalid_type_error : "Age must be a number" ,
} ) ;
Zod includes a handful of number-specific validations.
z . number ( ) . gt ( 5 ) ;
z . number ( ) . gte ( 5 ) ; // alias .min(5)
z . number ( ) . lt ( 5 ) ;
z . number ( ) . lte ( 5 ) ; // alias .max(5)
z . number ( ) . int ( ) ; // value must be an integer
z . number ( ) . positive ( ) ; // > 0
z . number ( ) . nonnegative ( ) ; // >= 0
z . number ( ) . negative ( ) ; // < 0
z . number ( ) . nonpositive ( ) ; // <= 0
z . number ( ) . multipleOf ( 5 ) ; // Evenly divisible by 5. Alias .step(5)
z . number ( ) . finite ( ) ; // value must be finite, not Infinity or -Infinity
z . number ( ) . safe ( ) ; // value must be between Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER
Secara opsional, Anda dapat lulus dalam argumen kedua untuk memberikan pesan kesalahan khusus.
z . number ( ) . lte ( 5 , { message : "this?is?too?big" } ) ;
Zod mencakup beberapa validasi khusus BigInt.
z . bigint ( ) . gt ( 5n ) ;
z . bigint ( ) . gte ( 5n ) ; // alias `.min(5n)`
z . bigint ( ) . lt ( 5n ) ;
z . bigint ( ) . lte ( 5n ) ; // alias `.max(5n)`
z . bigint ( ) . positive ( ) ; // > 0n
z . bigint ( ) . nonnegative ( ) ; // >= 0n
z . bigint ( ) . negative ( ) ; // < 0n
z . bigint ( ) . nonpositive ( ) ; // <= 0n
z . bigint ( ) . multipleOf ( 5n ) ; // Evenly divisible by 5n.
Anda dapat menyesuaikan pesan kesalahan tertentu saat membuat skema NAN.
const isNaN = z . nan ( {
required_error : "isNaN is required" ,
invalid_type_error : "isNaN must be 'not a number'" ,
} ) ;
Anda dapat menyesuaikan pesan kesalahan tertentu saat membuat skema boolean.
const isActive = z . boolean ( {
required_error : "isActive is required" ,
invalid_type_error : "isActive must be a boolean" ,
} ) ;
Gunakan z.date () untuk memvalidasi instance Date
.
z . date ( ) . safeParse ( new Date ( ) ) ; // success: true
z . date ( ) . safeParse ( "2022-01-12T00:00:00.000Z" ) ; // success: false
Anda dapat menyesuaikan pesan kesalahan tertentu saat membuat skema tanggal.
const myDateSchema = z . date ( {
required_error : "Please select a date and time" ,
invalid_type_error : "That's not a date!" ,
} ) ;
Zod menyediakan beberapa validasi khusus tanggal.
z . date ( ) . min ( new Date ( "1900-01-01" ) , { message : "Too old" } ) ;
z . date ( ) . max ( new Date ( ) , { message : "Too young!" } ) ;
Paksaan sampai saat ini
Since zod 3.20, use z.coerce.date()
to pass the input through new Date(input)
.
const dateSchema = z . coerce . date ( ) ;
type DateSchema = z . infer < typeof dateSchema > ;
// type DateSchema = Date
/* valid dates */
console . log ( dateSchema . safeParse ( "2023-01-10T00:00:00.000Z" ) . success ) ; // true
console . log ( dateSchema . safeParse ( "2023-01-10" ) . success ) ; // true
console . log ( dateSchema . safeParse ( "1/10/23" ) . success ) ; // true
console . log ( dateSchema . safeParse ( new Date ( "1/10/23" ) ) . success ) ; // true
/* invalid dates */
console . log ( dateSchema . safeParse ( "2023-13-10" ) . success ) ; // false
console . log ( dateSchema . safeParse ( "0000-00-00" ) . success ) ; // false
Untuk versi ZOD yang lebih tua, gunakan z.preprocess
seperti yang dijelaskan dalam utas ini.
const FishEnum = z . enum ( [ "Salmon" , "Tuna" , "Trout" ] ) ;
type FishEnum = z . infer < typeof FishEnum > ;
// 'Salmon' | 'Tuna' | 'Trout'
z.enum
adalah cara Zod-asli untuk mendeklarasikan skema dengan set tetap dari nilai string yang diijinkan. Lewati array nilai langsung ke z.enum()
. Atau, gunakan as const
untuk menentukan nilai enum Anda sebagai tuple string. Lihat Dokumen Pernyataan Const untuk detailnya.
const VALUES = [ "Salmon" , "Tuna" , "Trout" ] as const ;
const FishEnum = z . enum ( VALUES ) ;
Ini tidak diperbolehkan, karena Zod tidak dapat menyimpulkan nilai yang tepat dari setiap elemen.
const fish = [ "Salmon" , "Tuna" , "Trout" ] ;
const FishEnum = z . enum ( fish ) ;
.enum
Untuk mendapatkan pelengkapan otomatis dengan zod enum, gunakan properti .enum
dari skema Anda:
FishEnum . enum . Salmon ; // => autocompletes
FishEnum . enum ;
/*
=> {
Salmon: "Salmon",
Tuna: "Tuna",
Trout: "Trout",
}
*/
Anda juga dapat mengambil daftar opsi sebagai tuple dengan properti .options
:
FishEnum . options ; // ["Salmon", "Tuna", "Trout"];
.exclude/.extract()
Anda dapat membuat himpunan bagian zod enum dengan metode .exclude
dan .extract
.
const FishEnum = z . enum ( [ "Salmon" , "Tuna" , "Trout" ] ) ;
const SalmonAndTrout = FishEnum . extract ( [ "Salmon" , "Trout" ] ) ;
const TunaOnly = FishEnum . exclude ( [ "Salmon" , "Trout" ] ) ;
Zod enums adalah pendekatan yang disarankan untuk mendefinisikan dan memvalidasi enum. Tetapi jika Anda perlu memvalidasi terhadap enum dari perpustakaan pihak ketiga (atau Anda tidak ingin menulis ulang enum yang ada), Anda dapat menggunakan z.nativeEnum()
.
Enum numerik
enum Fruits {
Apple ,
Banana ,
}
const FruitEnum = z . nativeEnum ( Fruits ) ;
type FruitEnum = z . infer < typeof FruitEnum > ; // Fruits
FruitEnum . parse ( Fruits . Apple ) ; // passes
FruitEnum . parse ( Fruits . Banana ) ; // passes
FruitEnum . parse ( 0 ) ; // passes
FruitEnum . parse ( 1 ) ; // passes
FruitEnum . parse ( 3 ) ; // fails
String enums
enum Fruits {
Apple = "apple" ,
Banana = "banana" ,
Cantaloupe , // you can mix numerical and string enums
}
const FruitEnum = z . nativeEnum ( Fruits ) ;
type FruitEnum = z . infer < typeof FruitEnum > ; // Fruits
FruitEnum . parse ( Fruits . Apple ) ; // passes
FruitEnum . parse ( Fruits . Cantaloupe ) ; // passes
FruitEnum . parse ( "apple" ) ; // passes
FruitEnum . parse ( "banana" ) ; // passes
FruitEnum . parse ( 0 ) ; // passes
FruitEnum . parse ( "Cantaloupe" ) ; // fails
Const enums
Fungsi .nativeEnum()
berfungsi as const
juga.as const
membutuhkan TypeScript 3.4+!
const Fruits = {
Apple : "apple" ,
Banana : "banana" ,
Cantaloupe : 3 ,
} as const ;
const FruitEnum = z . nativeEnum ( Fruits ) ;
type FruitEnum = z . infer < typeof FruitEnum > ; // "apple" | "banana" | 3
FruitEnum . parse ( "apple" ) ; // passes
FruitEnum . parse ( "banana" ) ; // passes
FruitEnum . parse ( 3 ) ; // passes
FruitEnum . parse ( "Cantaloupe" ) ; // fails
Anda dapat mengakses objek yang mendasarinya dengan properti .enum
:
FruitEnum . enum . Apple ; // "apple"
Anda dapat membuat skema apa pun opsional dengan z.optional()
. Ini membungkus skema dalam contoh ZodOptional
dan mengembalikan hasilnya.
const schema = z . optional ( z . string ( ) ) ;
schema . parse ( undefined ) ; // => returns undefined
type A = z . infer < typeof schema > ; // string | undefined
Untuk kenyamanan, Anda juga dapat memanggil metode .optional()
pada skema yang ada.
const user = z . object ( {
username : z . string ( ) . optional ( ) ,
} ) ;
type C = z . infer < typeof user > ; // { username?: string | undefined };
Anda dapat mengekstrak skema yang dibungkus dari contoh ZodOptional
dengan .unwrap()
.
const stringSchema = z . string ( ) ;
const optionalString = stringSchema . optional ( ) ;
optionalString . unwrap ( ) === stringSchema ; // true
Demikian pula, Anda dapat membuat tipe nullable dengan z.nullable()
.
const nullableString = z . nullable ( z . string ( ) ) ;
nullableString . parse ( "asdf" ) ; // => "asdf"
nullableString . parse ( null ) ; // => null
Atau gunakan metode .nullable()
.
const E = z . string ( ) . nullable ( ) ; // equivalent to nullableString
type E = z . infer < typeof E > ; // string | null
Ekstrak skema batin dengan .unwrap()
.
const stringSchema = z . string ( ) ;
const nullableString = stringSchema . nullable ( ) ;
nullableString . unwrap ( ) === stringSchema ; // true
// all properties are required by default
const Dog = z . object ( {
name : z . string ( ) ,
age : z . number ( ) ,
} ) ;
// extract the inferred type like this
type Dog = z . infer < typeof Dog > ;
// equivalent to:
type Dog = {
name : string ;
age : number ;
} ;
.shape
Gunakan .shape
untuk mengakses skema untuk kunci tertentu.
Dog . shape . name ; // => string schema
Dog . shape . age ; // => number schema
.keyof
Gunakan .keyof
untuk membuat skema ZodEnum
dari kunci skema objek.
const keySchema = Dog . keyof ( ) ;
keySchema ; // ZodEnum<["name", "age"]>
.extend
You can add additional fields to an object schema with the .extend
method.
const DogWithBreed = Dog . extend ( {
breed : z . string ( ) ,
} ) ;
Anda dapat menggunakan .extend
untuk menimpa bidang! Hati -hati dengan kekuatan ini!
.merge
Equivalent to A.extend(B.shape)
.
const BaseTeacher = z . object ( { students : z . array ( z . string ( ) ) } ) ;
const HasID = z . object ( { id : z . string ( ) } ) ;
const Teacher = BaseTeacher . merge ( HasID ) ;
type Teacher = z . infer < typeof Teacher > ; // => { students: string[], id: string }
Jika kedua skema berbagi kunci, sifat -sifat B mengesampingkan properti A. Skema yang dikembalikan juga mewarisi kebijakan "unknownkeys" (strip/ketat/passthrough) dan skema catchall dari B.
.pick/.omit
Terinspirasi oleh tipe utilitas Pick
dan Omit
-in TypeScript, semua skema objek ZOD memiliki metode .pick
dan .omit
yang mengembalikan versi yang dimodifikasi. Pertimbangkan skema resep ini:
const Recipe = z . object ( {
id : z . string ( ) ,
name : z . string ( ) ,
ingredients : z . array ( z . string ( ) ) ,
} ) ;
Untuk hanya menyimpan kunci tertentu, gunakan .pick
.
const JustTheName = Recipe . pick ( { name : true } ) ;
type JustTheName = z . infer < typeof JustTheName > ;
// => { name: string }
Untuk menghapus kunci tertentu, gunakan .omit
.
const NoIDRecipe = Recipe . omit ( { id : true } ) ;
type NoIDRecipe = z . infer < typeof NoIDRecipe > ;
// => { name: string, ingredients: string[] }
.partial
Terinspirasi oleh tipe utilitas TypeScript built-in parsial, metode .partial
membuat semua properti opsional.
Mulai dari objek ini:
const user = z . object ( {
email : z . string ( ) ,
username : z . string ( ) ,
} ) ;
// { email: string; username: string }
Kita dapat membuat versi parsial:
const partialUser = user . partial ( ) ;
// { email?: string | undefined; username?: string | undefined }
Anda juga dapat menentukan properti mana yang akan membuat opsional:
const optionalEmail = user . partial ( {
email : true ,
} ) ;
/*
{
email?: string | undefined;
username: string
}
*/
.deepPartial
Metode .partial
dangkal - hanya berlaku satu tingkat. Ada juga versi "mendalam":
const user = z . object ( {
username : z . string ( ) ,
location : z . object ( {
latitude : z . number ( ) ,
longitude : z . number ( ) ,
} ) ,
strings : z . array ( z . object ( { value : z . string ( ) } ) ) ,
} ) ;
const deepPartialUser = user . deepPartial ( ) ;
/*
{
username?: string | undefined,
location?: {
latitude?: number | undefined;
longitude?: number | undefined;
} | undefined,
strings?: { value?: string}[]
}
*/
Keterbatasan Penting: Partial yang dalam hanya bekerja seperti yang diharapkan dalam hierarki objek, array, dan tupel.
.required
Contrary to the .partial
method, the .required
method makes all properties required.
Mulai dari objek ini:
const user = z
. object ( {
email : z . string ( ) ,
username : z . string ( ) ,
} )
. partial ( ) ;
// { email?: string | undefined; username?: string | undefined }
Kami dapat membuat versi yang diperlukan:
const requiredUser = user . required ( ) ;
// { email: string; username: string }
Anda juga dapat menentukan properti mana yang diperlukan:
const requiredEmail = user . required ( {
email : true ,
} ) ;
/*
{
email: string;
username?: string | undefined;
}
*/
.passthrough
Secara default, skema objek zod menghilangkan tombol yang tidak diakui selama penguraian.
const person = z . object ( {
name : z . string ( ) ,
} ) ;
person . parse ( {
name : "bob dylan" ,
extraKey : 61 ,
} ) ;
// => { name: "bob dylan" }
// extraKey has been stripped
Sebaliknya, jika Anda ingin melewati tombol yang tidak diketahui, gunakan .passthrough()
.
person . passthrough ( ) . parse ( {
name : "bob dylan" ,
extraKey : 61 ,
} ) ;
// => { name: "bob dylan", extraKey: 61 }
.strict
Secara default, skema objek zod menghilangkan tombol yang tidak diakui selama penguraian. Anda dapat melarang kunci yang tidak diketahui dengan .strict()
. Jika ada kunci yang tidak diketahui dalam input, Zod akan melakukan kesalahan.
const person = z
. object ( {
name : z . string ( ) ,
} )
. strict ( ) ;
person . parse ( {
name : "bob dylan" ,
extraKey : 61 ,
} ) ;
// => throws ZodError
.strip
Anda dapat menggunakan metode .strip
untuk mengatur ulang skema objek ke perilaku default (mengupas tombol yang tidak diakui).
.catchall
Anda dapat melewati skema "catchall" ke dalam skema objek. Semua kunci yang tidak diketahui akan divalidasi terhadapnya.
const person = z
. object ( {
name : z . string ( ) ,
} )
. catchall ( z . number ( ) ) ;
person . parse ( {
name : "bob dylan" ,
validExtraKey : 61 , // works fine
} ) ;
person . parse ( {
name : "bob dylan" ,
validExtraKey : false , // fails
} ) ;
// => throws ZodError
Menggunakan .catchall()
menyingkirkan .passthrough()
, .strip()
, atau .strict()
. Semua kunci sekarang dianggap "diketahui".
const stringArray = z . array ( z . string ( ) ) ;
// equivalent
const stringArray = z . string ( ) . array ( ) ;
Hati -hati dengan metode .array()
. Ini mengembalikan instance ZodArray
baru. Ini berarti urutan yang Anda sebut metode. Misalnya:
z . string ( ) . optional ( ) . array ( ) ; // (string | undefined)[]
z . string ( ) . array ( ) . optional ( ) ; // string[] | undefined
.element
Gunakan .element
untuk mengakses skema untuk elemen array.
stringArray . element ; // => string schema
.nonempty
Jika Anda ingin memastikan bahwa array berisi setidaknya satu elemen, gunakan .nonempty()
.
const nonEmptyStrings = z . string ( ) . array ( ) . nonempty ( ) ;
// the inferred type is now
// [string, ...string[]]
nonEmptyStrings . parse ( [ ] ) ; // throws: "Array cannot be empty"
nonEmptyStrings . parse ( [ "Ariana Grande" ] ) ; // passes
Anda secara opsional dapat menentukan pesan kesalahan khusus:
// optional custom error message
const nonEmptyStrings = z . string ( ) . array ( ) . nonempty ( {
message : "Can't be empty!" ,
} ) ;
.min/.max/.length
z . string ( ) . array ( ) . min ( 5 ) ; // must contain 5 or more items
z . string ( ) . array ( ) . max ( 5 ) ; // must contain 5 or fewer items
z . string ( ) . array ( ) . length ( 5 ) ; // must contain 5 items exactly
Tidak seperti .nonempty()
Metode ini tidak mengubah tipe yang disimpulkan.
Tidak seperti array, tupel memiliki jumlah elemen yang tetap dan setiap elemen dapat memiliki jenis yang berbeda.
const athleteSchema = z . tuple ( [
z . string ( ) , // name
z . number ( ) , // jersey number
z . object ( {
pointsScored : z . number ( ) ,
} ) , // statistics
] ) ;
type Athlete = z . infer < typeof athleteSchema > ;
// type Athlete = [string, number, { pointsScored: number }]
Argumen variadik ("istirahat") dapat ditambahkan dengan metode .rest
.
const variadicTuple = z . tuple ( [ z . string ( ) ] ) . rest ( z . number ( ) ) ;
const result = variadicTuple . parse ( [ "hello" , 1 , 2 , 3 ] ) ;
// => [string, ...number[]];
Zod termasuk metode z.union
bawaan untuk menyusun "atau" tipe.
const stringOrNumber = z . union ( [ z . string ( ) , z . number ( ) ] ) ;
stringOrNumber . parse ( "foo" ) ; // passes
stringOrNumber . parse ( 14 ) ; // passes
Zod will test the input against each of the "options" in order and return the first value that validates successfully.
Untuk kenyamanan, Anda juga dapat menggunakan metode .or
:
const stringOrNumber = z . string ( ) . or ( z . number ( ) ) ;
Validasi string opsional:
To validate an optional form input, you can union the desired string validation with an empty string literal.
Contoh ini memvalidasi input yang opsional tetapi perlu berisi URL yang valid:
const optionalUrl = z . union ( [ z . string ( ) . url ( ) . nullish ( ) , z . literal ( "" ) ] ) ;
console . log ( optionalUrl . safeParse ( undefined ) . success ) ; // true
console . log ( optionalUrl . safeParse ( null ) . success ) ; // true
console . log ( optionalUrl . safeParse ( "" ) . success ) ; // true
console . log ( optionalUrl . safeParse ( "https://zod.dev" ) . success ) ; // true
console . log ( optionalUrl . safeParse ( "not a valid url" ) . success ) ; // false
Persatuan yang didiskriminasi adalah persatuan skema objek yang semuanya memiliki kunci tertentu.
type MyUnion =
| { status : "success" ; data : string }
| { status : "failed" ; error : Error } ;
Serikat pekerja semacam itu dapat diwakili dengan metode z.discriminatedUnion
. Ini memungkinkan evaluasi yang lebih cepat, karena Zod dapat memeriksa kunci diskriminator ( status
dalam contoh di atas) untuk menentukan skema mana yang harus digunakan untuk menguraikan input. Ini membuat parsing lebih efisien dan memungkinkan Zod melaporkan kesalahan yang lebih ramah.
Dengan metode Dasar Union, input diuji terhadap masing -masing "opsi" yang disediakan, dan dalam kasus ketidakabsahan, masalah untuk semua "opsi" ditunjukkan dalam kesalahan ZOD. Di sisi lain, serikat yang didiskriminasi memungkinkan untuk memilih hanya salah satu dari "opsi", menguji terhadapnya, dan hanya menunjukkan masalah yang terkait dengan "opsi" ini.
const myUnion = z . discriminatedUnion ( "status" , [
z . object ( { status : z . literal ( "success" ) , data : z . string ( ) } ) ,
z . object ( { status : z . literal ( "failed" ) , error : z . instanceof ( Error ) } ) ,
] ) ;
myUnion . parse ( { status : "success" , data : "yippie ki yay" } ) ;
Anda dapat mengekstrak referensi ke array skema dengan properti .options
.
myUnion . options ; // [ZodObject<...>, ZodObject<...>]
Untuk menggabungkan dua atau lebih serikat yang didiskriminasi, gunakan .options
dengan destruktur.
const A = z . discriminatedUnion ( "status" , [
/* options */
] ) ;
const B = z . discriminatedUnion ( "status" , [
/* options */
] ) ;
const AB = z . discriminatedUnion ( "status" , [ ... A . options , ... B . options ] ) ;
Skema rekaman digunakan untuk memvalidasi jenis seperti Record<string, number>
. Ini sangat berguna untuk menyimpan atau caching item dengan ID.
const User = z . object ( { name : z . string ( ) } ) ;
const UserStore = z . record ( z . string ( ) , User ) ;
type UserStore = z . infer < typeof UserStore > ;
// => Record<string, { name: string }>
The schema and inferred type can be used like so:
const userStore : UserStore = { } ;
userStore [ "77d2586b-9e8e-4ecf-8b21-ea7e0530eadd" ] = {
name : "Carlotta" ,
} ; // passes
userStore [ "77d2586b-9e8e-4ecf-8b21-ea7e0530eadd" ] = {
whatever : "Ice cream sundae" ,
} ; // TypeError
A note on numerical keys
Sementara z.record(keyType, valueType)
dapat menerima tipe kunci numerik dan tipe rekaman bawaan TypeScript adalah Record<KeyType, ValueType>
, sulit untuk mewakili Record<number, any>
di Zod.
Ternyata, perilaku TypeScript di sekitar [k: number]
sedikit tidak intuitif:
const testMap : { [ k : number ] : string } = {
1 : "one" ,
} ;
for ( const key in testMap ) {
console . log ( ` ${ key } : ${ typeof key } ` ) ;
}
// prints: `1: string`
Seperti yang Anda lihat, JavaScript secara otomatis melemparkan semua tombol objek ke string di bawah kap. Karena Zod mencoba untuk menjembatani kesenjangan antara jenis statis dan runtime, tidak masuk akal untuk memberikan cara membuat skema rekaman dengan kunci numerik, karena tidak ada yang namanya kunci numerik dalam runtime javascript.
const stringNumberMap = z . map ( z . string ( ) , z . number ( ) ) ;
type StringNumberMap = z . infer < typeof stringNumberMap > ;
// type StringNumberMap = Map<string, number>
const numberSet = z . set ( z . number ( ) ) ;
type NumberSet = z . infer < typeof numberSet > ;
// type NumberSet = Set<number>
Set skema dapat dibatasi lebih lanjut dengan metode utilitas berikut.
z . set ( z . string ( ) ) . nonempty ( ) ; // must contain at least one item
z . set ( z . string ( ) ) . min ( 5 ) ; // must contain 5 or more items
z . set ( z . string ( ) ) . max ( 5 ) ; // must contain 5 or fewer items
z . set ( z . string ( ) ) . size ( 5 ) ; // must contain 5 items exactly
Persimpangan berguna untuk membuat tipe "logis dan". Ini berguna untuk memotong dua jenis objek.
const Person = z . object ( {
name : z . string ( ) ,
} ) ;
const Employee = z . object ( {
role : z . string ( ) ,
} ) ;
const EmployedPerson = z . intersection ( Person , Employee ) ;
// equivalent to:
const EmployedPerson = Person . and ( Employee ) ;
Meskipun dalam banyak kasus, disarankan untuk menggunakan A.merge(B)
untuk menggabungkan dua objek. Metode .merge
mengembalikan instance ZodObject
baru, sedangkan A.and(B)
mengembalikan instance ZodIntersection
yang kurang berguna yang tidak memiliki metode objek umum seperti pick
dan omit
.
const a = z . union ( [ z . number ( ) , z . string ( ) ] ) ;
const b = z . union ( [ z . number ( ) , z . boolean ( ) ] ) ;
const c = z . intersection ( a , b ) ;
type c = z . infer < typeof c > ; // => number
Anda dapat mendefinisikan skema rekursif di ZOD, tetapi karena keterbatasan naskah, jenisnya tidak dapat disimpulkan secara statis. Alih -alih, Anda harus mendefinisikan definisi jenis secara manual, dan menyediakannya untuk Zod sebagai "petunjuk tipe".
const baseCategorySchema = z . object ( {
name : z . string ( ) ,
} ) ;
type Category = z . infer < typeof baseCategorySchema > & {
subcategories : Category [ ] ;
} ;
const categorySchema : z . ZodType < Category > = baseCategorySchema . extend ( {
subcategories : z . lazy ( ( ) => categorySchema . array ( ) ) ,
} ) ;
categorySchema . parse ( {
name : "People" ,
subcategories : [
{
name : "Politicians" ,
subcategories : [
{
name : "Presidents" ,
subcategories : [ ] ,
} ,
] ,
} ,
] ,
} ) ; // passes
Terima kasih kepada Crasite untuk contoh ini.
Saat menggunakan z.ZodType
dengan z.ZodEffects
( .refine
, .transform
, preprocess
, dll ...), Anda perlu menentukan jenis input dan output skema. z.ZodType<Output, z.ZodTypeDef, Input>
const isValidId = ( id : string ) : id is `${ string } /${ string } ` =>
id . split ( "/" ) . length === 2 ;
const baseSchema = z . object ( {
id : z . string ( ) . refine ( isValidId ) ,
} ) ;
type Input = z . input < typeof baseSchema > & {
children : Input [ ] ;
} ;
type Output = z . output < typeof baseSchema > & {
children : Output [ ] ;
} ;
const schema : z . ZodType < Output , z . ZodTypeDef , Input > = baseSchema . extend ( {
children : z . lazy ( ( ) => schema . array ( ) ) ,
} ) ;
Terima kasih kepada Marcus13371337 dan Joelbeeldi untuk contoh ini.
Jika Anda ingin memvalidasi nilai JSON, Anda dapat menggunakan cuplikan di bawah ini.
const literalSchema = z . union ( [ z . string ( ) , z . number ( ) , z . boolean ( ) , z . null ( ) ] ) ;
type Literal = z . infer < typeof literalSchema > ;
type Json = Literal | { [ key : string ] : Json } | Json [ ] ;
const jsonSchema : z . ZodType < Json > = z . lazy ( ( ) =>
z . union ( [ literalSchema , z . array ( jsonSchema ) , z . record ( jsonSchema ) ] )
) ;
jsonSchema . parse ( data ) ;
Terima kasih kepada Ggoodman karena telah menyarankan ini.
Meskipun mendukung skema rekursif, lulus data siklus ke ZOD akan menyebabkan loop tak terbatas dalam beberapa kasus.
Untuk mendeteksi objek siklus sebelum menyebabkan masalah, pertimbangkan pendekatan ini.
const numberPromise = z . promise ( z . number ( ) ) ;
"Parsing" bekerja sedikit berbeda dengan skema janji. Validasi terjadi dalam dua bagian:
.then
dan .catch
Metode.)..then
untuk melampirkan langkah validasi tambahan ke janji yang ada. Anda harus menggunakan .catch
pada janji yang dikembalikan untuk menangani kegagalan validasi. numberPromise . parse ( "tuna" ) ;
// ZodError: Non-Promise type: string
numberPromise . parse ( Promise . resolve ( "tuna" ) ) ;
// => Promise<number>
const test = async ( ) => {
await numberPromise . parse ( Promise . resolve ( "tuna" ) ) ;
// ZodError: Non-number type: string
await numberPromise . parse ( Promise . resolve ( 3.14 ) ) ;
// => 3.14
} ;
Anda dapat menggunakan z.instanceof
untuk memeriksa bahwa input adalah instance dari suatu kelas. Ini berguna untuk memvalidasi input terhadap kelas yang diekspor dari perpustakaan pihak ketiga.
class Test {
name : string ;
}
const TestSchema = z . instanceof ( Test ) ;
const blob : any = "whatever" ;
TestSchema . parse ( new Test ( ) ) ; // passes
TestSchema . parse ( blob ) ; // throws
Zod juga memungkinkan Anda mendefinisikan "skema fungsi". This makes it easy to validate the inputs and outputs of a function without intermixing your validation code and "business logic".
Anda dapat membuat skema fungsi dengan z.function(args, returnType)
.
const myFunction = z . function ( ) ;
type myFunction = z . infer < typeof myFunction > ;
// => ()=>unknown
Tentukan input dan output.
const myFunction = z
. function ( )
. args ( z . string ( ) , z . number ( ) ) // accepts an arbitrary number of arguments
. returns ( z . boolean ( ) ) ;
type myFunction = z . infer < typeof myFunction > ;
// => (arg0: string, arg1: number)=>boolean
Skema fungsi memiliki metode .implement()
yang menerima fungsi dan mengembalikan fungsi baru yang secara otomatis memvalidasi input dan outputnya.
const trimmedLength = z
. function ( )
. args ( z . string ( ) ) // accepts an arbitrary number of arguments
. returns ( z . number ( ) )
. implement ( ( x ) => {
// TypeScript knows x is a string!
return x . trim ( ) . length ;
} ) ;
trimmedLength ( "sandwich" ) ; // => 8
trimmedLength ( " asdf " ) ; // => 4
If you only care about validating inputs, just don't call the .returns()
method. Jenis output akan disimpulkan dari implementasi.
Anda dapat menggunakan opsi
z.void()
jika fungsi Anda tidak mengembalikan apa pun. Ini akan memungkinkan Zod dengan benar menyimpulkan jenis fungsi yang dikembalikan kekosongan. (Fungsi yang membatalkan kembali benar-benar mengembalikan tidak ditentukan.)
const myFunction = z
. function ( )
. args ( z . string ( ) )
. implement ( ( arg ) => {
return [ arg . length ] ;
} ) ;
myFunction ; // (arg: string)=>number[]
Ekstrak skema input dan output dari skema fungsi.
myFunction . parameters ( ) ;
// => ZodTuple<[ZodString, ZodNumber]>
myFunction . returnType ( ) ;
// => ZodBoolean
Zod sekarang mendukung paksaan primitif tanpa perlu
.preprocess()
. Lihat dokumen paksaan untuk informasi lebih lanjut.
Biasanya Zod beroperasi di bawah paradigma "parse kemudian mengubah". Zod memvalidasi input terlebih dahulu, kemudian melewatinya melalui rantai fungsi transformasi. (For more information about transforms, read the .transform docs.)
Tetapi kadang -kadang Anda ingin menerapkan beberapa transformasi ke input sebelum penguraian terjadi. Kasus Penggunaan Umum: Ketik paksaan. Zod memungkinkan ini dengan z.preprocess()
.
const castToString = z . preprocess ( ( val ) => String ( val ) , z . string ( ) ) ;
Ini mengembalikan instance ZodEffects
. ZodEffects
adalah kelas pembungkus yang berisi semua logika yang berkaitan dengan preprocessing, penyempurnaan, dan transformasi.
Anda dapat membuat skema ZOD untuk tipe TypeScript apa pun dengan menggunakan z.custom()
. Ini berguna untuk membuat skema untuk jenis yang tidak didukung oleh Zod di luar kotak, seperti literal string template.
const px = z . custom < `${ number } px` > ( ( val ) => {
return typeof val === "string" ? / ^d+px$ / . test ( val ) : false ;
} ) ;
type px = z . infer < typeof px > ; // `${number}px`
px . parse ( "42px" ) ; // "42px"
px . parse ( "42vw" ) ; // throws;
Jika Anda tidak memberikan fungsi validasi, ZOD akan mengizinkan nilai apa pun. Ini bisa berbahaya!
z . custom < { arg : string } > ( ) ; // performs no validation
Anda dapat menyesuaikan pesan kesalahan dan opsi lain dengan meloloskan argumen kedua. Parameter ini bekerja dengan cara yang sama seperti parameter Params dari .refine
.
z . custom < ... > ( ( val ) => ... , "custom error message" ) ;
Semua skema Zod berisi metode tertentu.
.parse
.parse(data: unknown): T
Diberikan skema ZOD, Anda dapat memanggil metode .parse
untuk memeriksa data
valid. Jika ya, nilai dikembalikan dengan informasi tipe penuh! Kalau tidak, kesalahan dilemparkan.
Penting: Nilai yang dikembalikan oleh
.parse
adalah klon dalam dari variabel yang Anda lewati.
const stringSchema = z . string ( ) ;
stringSchema . parse ( "fish" ) ; // => returns "fish"
stringSchema . parse ( 12 ) ; // throws error
.parseAsync
.parseAsync(data:unknown): Promise<T>
Jika Anda menggunakan penyempurnaan asinkron atau mengubah (lebih lanjut tentang itu nanti), Anda harus menggunakan .parseAsync
.
const stringSchema = z . string ( ) . refine ( async ( val ) => val . length <= 8 ) ;
await stringSchema . parseAsync ( "hello" ) ; // => returns "hello"
await stringSchema . parseAsync ( "hello world" ) ; // => throws error
.safeParse
.safeParse(data:unknown): { success: true; data: T; } | { success: false; error: ZodError; }
Jika Anda tidak ingin Zod melakukan kesalahan saat validasi gagal, gunakan .safeParse
. Metode ini mengembalikan objek yang berisi data yang berhasil diuraikan atau instance zoderror yang berisi informasi terperinci tentang masalah validasi.
stringSchema . safeParse ( 12 ) ;
// => { success: false; error: ZodError }
stringSchema . safeParse ( "billie" ) ;
// => { success: true; data: 'billie' }
Hasilnya adalah persatuan yang didiskriminasi , sehingga Anda dapat menangani kesalahan dengan sangat mudah:
const result = stringSchema . safeParse ( "billie" ) ;
if ( ! result . success ) {
// handle error then return
result . error ;
} else {
// do something
result . data ;
}
.safeParseAsync
Alias:
.spa
Versi safeParse
yang asinkron.
await stringSchema . safeParseAsync ( "billie" ) ;
Untuk kenyamanan, ini telah alias ke .spa
:
await stringSchema . spa ( "billie" ) ;
.refine
.refine(validator: (data:T)=>any, params?: RefineParams)
Zod memungkinkan Anda memberikan logika validasi khusus melalui penyempurnaan . (Untuk fitur canggih seperti membuat beberapa masalah dan menyesuaikan kode kesalahan, lihat .superRefine
.)
Zod dirancang untuk mencerminkan naskah secukupnya mungkin. Tetapi ada banyak yang disebut "jenis penyempurnaan" yang mungkin ingin Anda periksa yang tidak dapat direpresentasikan dalam sistem tipe TypeScript. Misalnya: Memeriksa bahwa nomor adalah integer atau bahwa string adalah alamat email yang valid.
Misalnya, Anda dapat menentukan pemeriksaan validasi khusus pada skema zod apa pun dengan .refine
:
const myString = z . string ( ) . refine ( ( val ) => val . length <= 255 , {
message : "String can't be more than 255 characters" ,
} ) ;
️ Fungsi penyempurnaan tidak boleh dilemparkan. Sebaliknya mereka harus mengembalikan nilai falsy untuk menandakan kegagalan.
Seperti yang Anda lihat, .refine
mengambil dua argumen.
T
- jenis skema yang disimpulkan) dan mengembalikan any
. Nilai kebenaran apa pun akan melewati validasi. (Prior to [email protected] the validation function had to return a boolean.) type RefineParams = {
// override error message
message ?: string ;
// appended to error path
path ?: ( string | number ) [ ] ;
// params object you can use to customize message
// in error map
params ?: object ;
} ;
Untuk kasus lanjutan, argumen kedua juga bisa menjadi fungsi yang mengembalikan RefineParams
.
const longString = z . string ( ) . refine (
( val ) => val . length > 10 ,
( val ) => ( { message : ` ${ val } is not more than 10 characters` } )
) ;
const passwordForm = z
. object ( {
password : z . string ( ) ,
confirm : z . string ( ) ,
} )
. refine ( ( data ) => data . password === data . confirm , {
message : "Passwords don't match" ,
path : [ "confirm" ] , // path of error
} ) ;
passwordForm . parse ( { password : "asdf" , confirm : "qwer" } ) ;
Karena Anda memberikan parameter path
, kesalahan yang dihasilkan adalah:
ZodError {
issues : [ {
"code" : "custom" ,
"path" : [ "confirm" ] ,
"message" : "Passwords don't match"
} ]
}
Penyempurnaan juga bisa Async:
const userId = z . string ( ) . refine ( async ( id ) => {
// verify that ID exists in database
return true ;
} ) ;
️ Jika Anda menggunakan penyempurnaan async, Anda harus menggunakan metode.parseAsync
untuk menguraikan data! Kalau tidak, Zod akan melakukan kesalahan.
Transformasi dan penyempurnaan dapat diselingi:
z . string ( )
. transform ( ( val ) => val . length )
. refine ( ( val ) => val > 25 ) ;
.superRefine
The .refine
method is actually syntactic sugar atop a more versatile (and verbose) method called superRefine
. Inilah contohnya:
const Strings = z . array ( z . string ( ) ) . superRefine ( ( val , ctx ) => {
if ( val . length > 3 ) {
ctx . addIssue ( {
code : z . ZodIssueCode . too_big ,
maximum : 3 ,
type : "array" ,
inclusive : true ,
message : "Too many items ?" ,
} ) ;
}
if ( val . length !== new Set ( val ) . size ) {
ctx . addIssue ( {
code : z . ZodIssueCode . custom ,
message : `No duplicates allowed.` ,
} ) ;
}
} ) ;
You can add as many issues as you like. Jika ctx.addIssue
tidak dipanggil selama pelaksanaan fungsi, validasi berlalu.
Biasanya penyempurnaan selalu membuat masalah dengan ZodIssueCode.custom
kode kesalahan, tetapi dengan superRefine
dimungkinkan untuk melemparkan masalah dari setiap ZodIssueCode
. Setiap kode masalah dijelaskan secara rinci dalam panduan penanganan kesalahan: error_handling.md.
Secara default, parsing akan berlanjut bahkan setelah pemeriksaan penyempurnaan gagal. Misalnya, jika Anda menggabungkan beberapa penyempurnaan, semuanya akan dieksekusi. Namun, mungkin diinginkan untuk membatalkan lebih awal untuk mencegah perbaikan kemudian dieksekusi. Untuk mencapai hal ini, berikan bendera fatal
ke ctx.addIssue
dan kembalikan z.NEVER
.
const schema = z . number ( ) . superRefine ( ( val , ctx ) => {
if ( val < 10 ) {
ctx . addIssue ( {
code : z . ZodIssueCode . custom ,
message : "should be >= 10" ,
fatal : true ,
} ) ;
return z . NEVER ;
}
if ( val !== 12 ) {
ctx . addIssue ( {
code : z . ZodIssueCode . custom ,
message : "should be twelve" ,
} ) ;
}
} ) ;
Jika Anda memberikan .refine()
.superRefine()
. Ini berguna jika Anda mencampur beberapa penyempurnaan dan transformasi rantai:
const schema = z
. object ( {
first : z . string ( ) ,
second : z . number ( ) ,
} )
. nullable ( )
. superRefine ( ( arg , ctx ) : arg is { first : string ; second : number } => {
if ( ! arg ) {
ctx . addIssue ( {
code : z . ZodIssueCode . custom , // customize your issue
message : "object should exist" ,
} ) ;
}
return z . NEVER ; // The return value is not used, but we need to return something to satisfy the typing
} )
// here, TS knows that arg is not null
. refine ( ( arg ) => arg . first === "bob" , "`first` is not `bob`!" ) ;
️ Anda harus menggunakanctx.addIssue()
alih -alih mengembalikan nilai boolean untuk menunjukkan apakah validasi berlalu. Jikactx.addIssue
tidak dipanggil selama pelaksanaan fungsi, validasi berlalu.
.transform
Untuk mengubah data setelah penguraian, gunakan metode transform
.
const stringToNumber = z . string ( ) . transform ( ( val ) => val . length ) ;
stringToNumber . parse ( "string" ) ; // => 6
Perhatikan bahwa stringToNumber
di atas adalah contoh dari subkelas ZodEffects
. Ini bukan contoh ZodString
. Jika Anda ingin menggunakan metode bawaan ZodString
(mis .email()
const emailToDomain = z
. string ( )
. email ( )
. transform ( ( val ) => val . split ( "@" ) [ 1 ] ) ;
emailToDomain . parse ( "[email protected]" ) ; // => example.com
Metode .transform
dapat secara bersamaan memvalidasi dan mengubah nilainya. Ini seringkali lebih sederhana dan kurang duplikat daripada merantai transform
dan refine
.
Seperti halnya .superRefine
, fungsi transformasi menerima objek ctx
dengan metode addIssue
yang dapat digunakan untuk mendaftarkan masalah validasi.
const numberInString = z . string ( ) . transform ( ( val , ctx ) => {
const parsed = parseInt ( val ) ;
if ( isNaN ( parsed ) ) {
ctx . addIssue ( {
code : z . ZodIssueCode . custom ,
message : "Not a number" ,
} ) ;
// This is a special symbol you can use to
// return early from the transform function.
// It has type `never` so it does not affect the
// inferred return type.
return z . NEVER ;
}
return parsed ;
} ) ;
Transformasi dan penyempurnaan dapat diselingi. Ini akan dieksekusi dalam urutan mereka dinyatakan.
const nameToGreeting = z
. string ( )
. transform ( ( val ) => val . toUpperCase ( ) )
. refine ( ( val ) => val . length > 15 )
. transform ( ( val ) => `Hello ${ val } ` )
. refine ( ( val ) => val . indexOf ( "!" ) === - 1 ) ;
Transformasi juga bisa async.
const IdToUser = z
. string ( )
. uuid ( )
. transform ( async ( id ) => {
return await getUserById ( id ) ;
} ) ;
️ Jika skema Anda mengandung transformasi asinkron, Anda harus menggunakan .parseasync () atau .safeparseasync () untuk menguraikan data. Otherwise Zod will throw an error.
.default
Anda dapat menggunakan Transforms untuk mengimplementasikan konsep "nilai default" di Zod.
const stringWithDefault = z . string ( ) . default ( "tuna" ) ;
stringWithDefault . parse ( undefined ) ; // => "tuna"
Secara opsional, Anda dapat melewati fungsi ke .default
yang akan dieksekusi ulang setiap kali nilai default perlu dihasilkan:
const numberWithRandomDefault = z . number ( ) . default ( Math . random ) ;
numberWithRandomDefault . parse ( undefined ) ; // => 0.4413456736055323
numberWithRandomDefault . parse ( undefined ) ; // => 0.1871840107401901
numberWithRandomDefault . parse ( undefined ) ; // => 0.7223408162401552
Secara konseptual, beginilah cara zod memproses nilai default:
undefined
, nilai default dikembalikan.describe
Gunakan .describe()
untuk menambahkan properti description
ke skema yang dihasilkan.
const documentedString = z
. string ( )
. describe ( "A useful bit of text, if you know what to do with it." ) ;
documentedString . description ; // A useful bit of text…
Ini dapat berguna untuk mendokumentasikan bidang, misalnya dalam skema JSON menggunakan perpustakaan seperti zod-to-json-schema
).
.catch
Gunakan .catch()
untuk memberikan "nilai tangkapan" untuk dikembalikan jika terjadi kesalahan parsing.
const numberWithCatch = z . number ( ) . catch ( 42 ) ;
numberWithCatch . parse ( 5 ) ; // => 5
numberWithCatch . parse ( "tuna" ) ; // => 42
Secara opsional, Anda dapat melewati fungsi ke .catch
yang akan dieksekusi ulang setiap kali nilai default perlu dihasilkan. Objek ctx
yang berisi kesalahan yang tertangkap akan diteruskan ke fungsi ini.
const numberWithRandomCatch = z . number ( ) . catch ( ( ctx ) => {
ctx . error ; // the caught ZodError
return Math . random ( ) ;
} ) ;
numberWithRandomCatch . parse ( "sup" ) ; // => 0.4413456736055323
numberWithRandomCatch . parse ( "sup" ) ; // => 0.1871840107401901
numberWithRandomCatch . parse ( "sup" ) ; // => 0.7223408162401552
Secara konseptual, beginilah cara zod memproses "nilai menangkap":
.optional
Metode kenyamanan yang mengembalikan versi opsional dari skema.
const optionalString = z . string ( ) . optional ( ) ; // string | undefined
// equivalent to
z . optional ( z . string ( ) ) ;
.nullable
Metode kenyamanan yang mengembalikan versi skema yang dapat dibatalkan.
const nullableString = z . string ( ) . nullable ( ) ; // string | null
// equivalent to
z . nullable ( z . string ( ) ) ;
.nullish
Metode kenyamanan yang mengembalikan versi skema "nullish". Skema nullish akan menerima baik undefined
dan null
. Baca lebih lanjut tentang konsep "nullish" dalam catatan rilis TypeScript 3.7.
const nullishString = z . string ( ) . nullish ( ) ; // string | null | undefined
// equivalent to
z . string ( ) . nullable ( ) . optional ( ) ;
.array
Metode kenyamanan yang mengembalikan skema array untuk jenis yang diberikan:
const stringArray = z . string ( ) . array ( ) ; // string[]
// equivalent to
z . array ( z . string ( ) ) ;
.promise
Metode kenyamanan untuk jenis janji:
const stringPromise = z . string ( ) . promise ( ) ; // Promise<string>
// equivalent to
z . promise ( z . string ( ) ) ;
.or
Metode kenyamanan untuk jenis serikat.
const stringOrNumber = z . string ( ) . or ( z . number ( ) ) ; // string | number
// equivalent to
z . union ( [ z . string ( ) , z . number ( ) ] ) ;
.and
Metode kenyamanan untuk membuat jenis persimpangan.
const nameAndAge = z
. object ( { name : z . string ( ) } )
. and ( z . object ( { age : z . number ( ) } ) ) ; // { name: string } & { age: number }
// equivalent to
z . intersection ( z . object ( { name : z . string ( ) } ) , z . object ( { age : z . number ( ) } ) ) ;
.brand
.brand<T>() => ZodBranded<this, B>
Sistem tipe TypeScript bersifat struktural, yang berarti bahwa dua jenis yang setara secara struktural dianggap sama.
type Cat = { name : string } ;
type Dog = { name : string } ;
const petCat = ( cat : Cat ) => { } ;
const fido : Dog = { name : "fido" } ;
petCat ( fido ) ; // works fine
Dalam beberapa kasus, dapat diinginkan untuk mensimulasikan pengetikan nominal di dalam naskah. Misalnya, Anda mungkin ingin menulis fungsi yang hanya menerima input yang telah divalidasi oleh Zod. Ini dapat dicapai dengan tipe bermerek (alias tipe buram ).
const Cat = z . object ( { name : z . string ( ) } ) . brand < "Cat" > ( ) ;
type Cat = z . infer < typeof Cat > ;
const petCat = ( cat : Cat ) => { } ;
// this works
const simba = Cat . parse ( { name : "simba" } ) ;
petCat ( simba ) ;
// this doesn't
petCat ( { name : "fido" } ) ;
Di bawah kap, ini bekerja dengan melampirkan "merek" ke jenis yang disimpulkan menggunakan tipe persimpangan. Dengan cara ini, struktur data polos/tidak bermerek tidak lagi dapat ditetapkan untuk jenis skema yang disimpulkan.
const Cat = z . object ( { name : z . string ( ) } ) . brand < "Cat" > ( ) ;
type Cat = z . infer < typeof Cat > ;
// {name: string} & {[symbol]: "Cat"}
Perhatikan bahwa jenis bermerek tidak mempengaruhi hasil runtime dari .parse
. Ini adalah konstruksi statis saja.
.readonly
.readonly() => ZodReadonly<this>
Metode ini mengembalikan instance skema ZodReadonly
yang mem -parsing input menggunakan skema dasar, kemudian memanggil Object.freeze()
pada hasilnya. Jenis yang disimpulkan juga ditandai sebagai readonly
.
const schema = z . object ( { name : z . string ( ) } ) . readonly ( ) ;
type schema = z . infer < typeof schema > ;
// Readonly<{name: string}>
const result = schema . parse ( { name : "fido" } ) ;
result . name = "simba" ; // error
Jenis yang disimpulkan menggunakan tipe readyly bawaan TypeScript saat relevan.
z . array ( z . string ( ) ) . readonly ( ) ;
// readonly string[]
z . tuple ( [ z . string ( ) , z . number ( ) ] ) . readonly ( ) ;
// readonly [string, number]
z . map ( z . string ( ) , z . date ( ) ) . readonly ( ) ;
// ReadonlyMap<string, Date>
z . set ( z . string ( ) ) . readonly ( ) ;
// ReadonlySet<string>
.pipe
Skema dapat dirantai menjadi "jaringan pipa" validasi. Ini berguna untuk dengan mudah memvalidasi hasilnya setelah .transform()
:
z . string ( )
. transform ( ( val ) => val . length )
. pipe ( z . number ( ) . min ( 5 ) ) ;
Metode .pipe()
mengembalikan instance ZodPipeline
.
.pipe()
untuk memperbaiki masalah umum dengan z.coerce
. Anda dapat membatasi input untuk jenis yang bekerja dengan baik dengan paksaan yang Anda pilih. Kemudian gunakan .pipe()
untuk menerapkan paksaan.
Tanpa input terbatas:
const toDate = z . coerce . date ( ) ;
// works intuitively
console . log ( toDate . safeParse ( "2023-01-01" ) . success ) ; // true
// might not be what you want
console . log ( toDate . safeParse ( null ) . success ) ; // true
dengan input terbatas:
const datelike = z . union ( [ z . number ( ) , z . string ( ) , z . date ( ) ] ) ;
const datelikeToDate = datelike . pipe ( z . coerce . date ( ) ) ;
// still works intuitively
console . log ( datelikeToDate . safeParse ( "2023-01-01" ) . success ) ; // true
// more likely what you want
console . log ( datelikeToDate . safeParse ( null ) . success ) ; // false
Anda juga dapat menggunakan teknik ini untuk menghindari paksaan yang melemparkan kesalahan yang tidak dibawa.
without constrained input:
const toBigInt = z . coerce . bigint ( ) ;
// works intuitively
console . log ( toBigInt . safeParse ( "42" ) ) ; // true
// probably not what you want
console . log ( toBigInt . safeParse ( null ) ) ; // throws uncaught error
dengan input terbatas:
const toNumber = z . number ( ) . or ( z . string ( ) ) . pipe ( z . coerce . number ( ) ) ;
const toBigInt = z . bigint ( ) . or ( toNumber ) . pipe ( z . coerce . bigint ( ) ) ;
// still works intuitively
console . log ( toBigInt . safeParse ( "42" ) . success ) ; // true
// error handled by zod, more likely what you want
console . log ( toBigInt . safeParse ( null ) . success ) ; // false
Anda dapat mengekstrak tipe skema apa pun dengan z.infer<typeof mySchema>
.
const A = z . string ( ) ;
type A = z . infer < typeof A > ; // string
const u : A = 12 ; // TypeError
const u : A = "asdf" ; // compiles
Bagaimana dengan transformasi?
Pada kenyataannya setiap skema ZOD secara internal melacak dua jenis: input dan output. Untuk sebagian besar skema (misalnya z.string()
) keduanya sama. Tetapi begitu Anda menambahkan transformasi ke dalam campuran, kedua nilai ini dapat menyimpang. Misalnya z.string().transform(val => val.length)
memiliki input string
dan output number
.
Anda dapat secara terpisah mengekstrak tipe input dan output seperti itu:
const stringToNumber = z . string ( ) . transform ( ( val ) => val . length ) ;
// ️ Important: z.infer returns the OUTPUT type!
type input = z . input < typeof stringToNumber > ; // string
type output = z . output < typeof stringToNumber > ; // number
// equivalent to z.output!
type inferred = z . infer < typeof stringToNumber > ; // number
Dengan generik TypeScript, Anda dapat menulis fungsi yang dapat digunakan kembali yang menerima skema Zod sebagai parameter. Ini memungkinkan Anda untuk membuat logika validasi khusus, transformasi skema, dan banyak lagi, sambil menjaga keamanan dan inferensi jenis.
When attempting to write a function that accepts a Zod schema as an input, it's tempting to try something like this:
function inferSchema < T > ( schema : z . ZodType < T > ) {
return schema ;
}
Pendekatan ini tidak benar, dan membatasi kemampuan Typescript untuk menyimpulkan argumen dengan benar. No matter what you pass in, the type of schema
will be an instance of ZodType
.
inferSchema ( z . string ( ) ) ;
// => ZodType<string>
This approach loses type information, namely which subclass the input actually is (in this case, ZodString
). That means you can't call any string-specific methods like .min()
on the result of inferSchema
.
A better approach is to infer the schema as a whole instead of merely its inferred type. You can do this with a utility type called z.ZodTypeAny
.
function inferSchema < T extends z . ZodTypeAny > ( schema : T ) {
return schema ;
}
inferSchema ( z . string ( ) ) ;
// => ZodString
ZodTypeAny
is just a shorthand forZodType<any, any, any>
, a type that is broad enough to match any Zod schema.
The Result is now fully and properly typed, and the type system can infer the specific subclass of the schema.
If you follow the best practice of using z.ZodTypeAny
as the generic parameter for your schema, you may encounter issues with the parsed data being typed as any
instead of the inferred type of the schema.
function parseData < T extends z . ZodTypeAny > ( data : unknown , schema : T ) {
return schema . parse ( data ) ;
}
parseData ( "sup" , z . string ( ) ) ;
// => any
Due to how TypeScript inference works, it is treating schema
like a ZodTypeAny
instead of the inferred type. You can fix this with a type cast using z.infer
.
function parseData < T extends z . ZodTypeAny > ( data : unknown , schema : T ) {
return schema . parse ( data ) as z . infer < T > ;
// ^^^^^^^^^^^^^^ <- add this
}
parseData ( "sup" , z . string ( ) ) ;
// => string
The ZodType
class has three generic parameters.
class ZodType <
Output = any ,
Def extends ZodTypeDef = ZodTypeDef ,
Input = Output
> { ... }
By constraining these in your generic input, you can limit what schemas are allowable as inputs to your function:
function makeSchemaOptional < T extends z . ZodType < string > > ( schema : T ) {
return schema . optional ( ) ;
}
makeSchemaOptional ( z . string ( ) ) ;
// works fine
makeSchemaOptional ( z . number ( ) ) ;
// Error: 'ZodNumber' is not assignable to parameter of type 'ZodType<string, ZodTypeDef, string>'
Zod provides a subclass of Error called ZodError
. ZodErrors contain an issues
array containing detailed information about the validation problems.
const result = z
. object ( {
name : z . string ( ) ,
} )
. safeParse ( { name : 12 } ) ;
if ( ! result . success ) {
result . error . issues ;
/* [
{
"code": "invalid_type",
"expected": "string",
"received": "number",
"path": [ "name" ],
"message": "Expected string, received number"
}
] */
}
For detailed information about the possible error codes and how to customize error messages, check out the dedicated error handling guide: ERROR_HANDLING.md
Zod's error reporting emphasizes completeness and correctness . If you are looking to present a useful error message to the end user, you should either override Zod's error messages using an error map (described in detail in the Error Handling guide) or use a third-party library like zod-validation-error
You can use the .format()
method to convert this error into a nested object.
const result = z
. object ( {
name : z . string ( ) ,
} )
. safeParse ( { name : 12 } ) ;
if ( ! result . success ) {
const formatted = result . error . format ( ) ;
/* {
name: { _errors: [ 'Expected string, received number' ] }
} */
formatted . name ?. _errors ;
// => ["Expected string, received number"]
}
There are a handful of other widely-used validation libraries, but all of them have certain design limitations that make for a non-ideal developer experience.
https://github.com/hapijs/joi
Doesn't support static type inference ?
https://github.com/jquense/yup
Yup is a full-featured library that was implemented first in vanilla JS, and later rewritten in TypeScript.
https://github.com/gcanti/io-ts
io-ts is an excellent library by gcanti. The API of io-ts heavily inspired the design of Zod.
In our experience, io-ts prioritizes functional programming purity over developer experience in many cases. This is a valid and admirable design goal, but it makes io-ts particularly hard to integrate into an existing codebase with a more procedural or object-oriented bias. For instance, consider how to define an object with optional properties in io-ts:
import * as t from "io-ts" ;
const A = t . type ( {
foo : t . string ,
} ) ;
const B = t . partial ( {
bar : t . number ,
} ) ;
const C = t . intersection ( [ A , B ] ) ;
type C = t . TypeOf < typeof C > ;
// returns { foo: string; bar?: number | undefined }
You must define the required and optional props in separate object validators, pass the optionals through t.partial
(which marks all properties as optional), then combine them with t.intersection
.
Consider the equivalent in Zod:
const C = z . object ( {
foo : z . string ( ) ,
bar : z . number ( ) . optional ( ) ,
} ) ;
type C = z . infer < typeof C > ;
// returns { foo: string; bar?: number | undefined }
This more declarative API makes schema definitions vastly more concise.
io-ts
also requires the use of gcanti's functional programming library fp-ts
to parse results and handle errors. This is another fantastic resource for developers looking to keep their codebase strictly functional. But depending on fp-ts
necessarily comes with a lot of intellectual overhead; a developer has to be familiar with functional programming concepts and the fp-ts
nomenclature to use the library.
fp-ts
compatibility[T, ...T[]]
)https://github.com/pelotom/runtypes
Good type inference support.
[T, ...T[]]
)https://github.com/sindresorhus/ow
Ow is focused on function input validation. It's a library that makes it easy to express complicated assert statements, but it doesn't let you parse untyped data. They support a much wider variety of types; Zod has a nearly one-to-one mapping with TypeScript's type system, whereas ow lets you validate several highly-specific types out of the box (eg int32Array
, see full list in their README).
If you want to validate function inputs, use function schemas in Zod! It's a much simpler approach that lets you reuse a function type declaration without repeating yourself (namely, copy-pasting a bunch of ow assertions at the beginning of every function). Also Zod lets you validate your return types as well, so you can be sure there won't be any unexpected data passed downstream.
View the changelog at CHANGELOG.md