https://zod.dev
Typscript-First-Schema-Validierung mit statischer Typinferenz
Diese Dokumente wurden in Chinesisch übersetzt.
npm
(Knoten/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()
verwenden, um gemeinsame Probleme mit z.coerce
zu beheben. ZOD ist eine Typscript-First-Schema-Deklaration und Validierungsbibliothek. Ich benutze den Begriff "Schema", um allgemein auf einen beliebigen Datentyp zu verweisen, von einer einfachen string
bis zu einem komplexen verschachtelten Objekt.
ZOD ist so konzipiert, dass es so Entwicklerfreundlichkeit wie möglich ist. Ziel ist es, doppelte Typdeklarationen zu beseitigen. Mit ZOD deklarieren Sie einmal einen Validator und ZOD schließt automatisch den statischen Typskriptyp ab. Es ist einfach, einfachere Typen in komplexe Datenstrukturen zu verfassen.
Einige andere großartige Aspekte:
.optional()
) geben eine neue Instanz zurückDas Sponsoring auf jeder Ebene wird geschätzt und gefördert. Wenn Sie ein kostenpflichtiges Produkt mit ZOD erstellt haben, sollten Sie eine der Unternehmensstufen in Betracht ziehen.
Die umfassendste User Management -Plattform
Clerk.com
|
|
|
|
|
PropelAuth | Cerbos | Skalar | Trigger.dev |
Transload | Unendlich | Whop | CryptojobSlist |
Schmucklos. | Inneggest | Storyblok | Mux |
Brandon Bayer | Jiří Brabec | Alex Johansson | Fungible Systeme |
Anpassungsfähig | Avana Brieftasche | Jason Lengstorf | Global Illumination, Inc. |
Masterborn | Ryan Palmer | Michael Sweeney | NEXTBASE |
Remote | Connor Sinnott | Mohammad-ali a'râbi | Supatool |
Es gibt eine wachsende Anzahl von Werkzeugen, die auf nativ auf dem neuesten Stand sind oder sie unterstützen! Wenn Sie ein Tool oder eine Bibliothek über ZOD erstellt haben, erzählen Sie mir davon auf Twitter oder starten Sie eine Diskussion. Ich werde es unten hinzufügen und es twittern.
tRPC
: End-to-End-Typ-APIs ohne GraphQL erstellen.@anatine/zod-nestjs
: Helfermethoden zur Verwendung von ZOD in einem NestJS-Projekt.zod-endpoints
: Vertrags-erste streng getippte Endpunkte mit ZOD. OpenAPI kompatibel.zhttp
: Eine openAPI -kompatible, streng getippte HTTP -Bibliothek mit ZOD -Eingabe- und Antwortvalidierung.domain-functions
: Entkoppeln Sie Ihre Geschäftslogik aus Ihrem Framework mit komponierbaren Funktionen. Mit erstklassigem Typ Inferenz von End bis Ende von ZOD-Schemata.@zodios/core
: Ein TypeScript -API -Client mit Laufzeit und kompilierende Zeitvalidierung, die von Axios und ZOD unterstützt wird.express-zod-api
: Erstellen Sie Express-basierte APIs mit I/O-Schema-Validierung und benutzerdefinierten Middlewares.tapiduck
: End-to-End-Typ-APIs mit ZOD und Express; Ein bisschen wie TRPC, aber einfacher.koa-zod-router
: Erstellen Sie die Typen von Typen in KOA mit E/A-Validierung mit ZOD.zod-sockets
: ZOD-betriebenes Socket. react-hook-form
: Ein Erstanbieter-ZOD-Resolver für die React-Hook-Form.zod-validation-error
: Generieren Sie benutzerfreundliche Fehlermeldungen von ZodError
.zod-formik-adapter
: Ein in der Gemeinde gepflegter Formik-Adapter für ZOD.react-zorm
: Standalone <form>
Erzeugung und Validierung für React unter Verwendung von ZOD.zodix
: ZOD -Dienstprogramme für FormData und UrlSearchParams in Remix -Ladern und -aktionen.conform
: Eine Typ -Validierungsbibliothek von Typen für die progressive Verbesserung von HTML -Formularen. Funktioniert mit Remix und Next.js.remix-params-helper
: Vereinfachen Sie die Integration von ZOD mit Standard-UrlSearchparams und FormData für Remix-Apps.formik-validator-zod
: Formik-konforme Validator-Bibliothek, die die Verwendung von ZOD mit Formik vereinfacht.zod-i18n-map
: Nützlich zum Übersetzen von ZOD-Fehlermeldungen.@modular-forms/solid
: Modulare Formbibliothek für SolidJs, die ZOD zur Validierung unterstützt.houseform
: Eine React -Formbibliothek, die ZOD zur Validierung verwendet.sveltekit-superforms
: Aufgeladene Formularbibliothek für Sveltekit mit ZOD-Validierung.mobx-zod-form
: Datenerbildungsbauer basierend auf MOBX & ZOD.@vee-validate/zod
: Formularbibliothek für VUE.js mit ZOD-Schema-Validierung.zod-form-renderer
: automatische Formfelder aus dem ZOD-Schema und rendern Sie sie mit React-Hook-Form mit E2E-Sicherheit. zod-to-ts
: Generieren Sie Typ-Skript-Definitionen aus ZOD-Schemata.zod-to-json-schema
: Umwandle deine ZOD-Schemas in JSON-Schemas.@anatine/zod-openapi
: Umwandelt ein ZOD-Schema in ein OpenAPI V3.x SchemaObject
.zod-fast-check
: Erzeugen Sie fast-check
Prüfungen aus ZOD-Schemata.zod-dto
: generieren nest.js dtos aus einem ZOD-Schema.fastify-type-provider-zod
: Erstellen Sie Fastify-Typ-Anbieter aus ZOD-Schemata.zod-to-openapi
: Erstellen Sie vollständige OpenAPI-Dokumente (Swagger) von ZOD, einschließlich Schemas, Endpunkten und Parametern.nestjs-graphql-zod
: Generiert NestJs GraphQL-Modellklassen aus ZOD-Schemata. Bietet GraphQL -Methodendekorateure, die mit ZOD -Schemata arbeiten.zod-openapi
: Erstellen Sie die Dokumentation von OpenAPI V3.x aus ZOD-Schemas.fastify-zod-openapi
: Anbieter des Fastify-Typs, Validierung, Serialisierung und @Fastify/Swagger-Unterstützung für ZOD-Schemas.typeschema
: Universaladapter für die Schema -Validierung.zodex
: (DE) Serialisierung für ZOD -Schemata ts-to-zod
: Umwandeln Sie Typscript-Definitionen in ZOD-Schemata.@runtyping/zod
: Generieren Sie ZOD aus statischen Typen und JSON -Schema.json-schema-to-zod
: Konvertieren Sie Ihre JSON-Schemas in ZOD-Schemas. Live -Demo.json-to-zod
: Umwandle JSON-Objekte in ZOD-Schemas. Live -Demo.graphql-codegen-typescript-validation-schema
: GraphQL-Codegenerator-Plugin zum Generieren von Formularvalidierungsschema aus Ihrem GraphQL-Schema.zod-prisma
: Generieren Sie ZOD-Schemata aus Ihrem Prisma-Schema.Supervillain
: Generieren Sie ZOD -Schemata aus Ihren Go -Strukturen.prisma-zod-generator
: Emit ZOD-Schemata aus Ihrem Prisma-Schema.drizzle-zod
: Machen Sie ZOD-Schemata aus Ihrem Nieselregenschema.prisma-trpc-generator
: Emit von TRPC-Routern und deren Validierungsschemas mit ZOD vollständig implementiert.zod-prisma-types
erstellen ZOD-Typen aus Ihren Prisma-Modellen.quicktype
: Konvertieren Sie JSON -Objekte und JSON -Schemas in ZOD -Schemas.@sanity-typed/zod
: Generieren Sie ZOD-Schemata aus Vernunftschemas.java-to-zod
: Pojos in ZOD-Schemata konvertierenOrval
: ZOD -Schemata aus OpenAPI -Schemata erzeugenKubb
: Generieren Sie SDKs und ZOD -Schemas aus Ihren OpenAPI -Schemas @anatine/zod-mock
: Generieren Sie Scheindaten aus einem ZOD-Schema. Angetrieben von faker.js.zod-mocking
: Generieren Sie Scheindaten aus Ihren ZOD-Schemas.zod-fixture
: Verwenden Sie Ihre ZOD-Schemas, um die Erzeugung nicht relevanter Testvorrichtungen auf deterministische Weise zu automatisieren.zocker
: Erzeugen Sie plausible Mockdaten aus Ihren Schemas.zodock
erzeugt Scheindaten basierend auf ZOD -Schemata.zod-schema-faker
generiert Scheindaten aus ZOD-Schemata. Angetrieben von @faker-js/faker und randexp.js freerstore
: Firestore Cost Optimizer.slonik
: Node.js Postgres Client mit starker ZOD -Integration.schemql
: Verbessert Ihren SQL -Workflow durch Kombination von RAW SQL mit gezielter Sicherheitstyp- und Schema -Validierung.soly
: Erstellen Sie CLI -Anwendungen mit ZOD.pastel
: Erstellen Sie CLI -Anwendungen mit React, ZOD und Tinte.zod-xlsx
: Ein XLSX-basierter Ressourcenvalidator mit ZOD-Schemas.znv
: Analyse und Validierung von Typ-Safe-Umgebungen für Node.js mit ZOD-Schemata.zod-config
: Laden Sie Konfigurationen über mehrere Quellen mit flexiblen Adaptern hinweg, um die Sicherheit mit ZOD zu gewährleisten.unplugin-environment
: Ein Plugin zum Laden von Umgebungsvariablen sicher mit Schema-Validierung, einfach mit virtuellem Modul, Typ-Safe mit IntelliSense und besserer DX? Angetrieben von Zod. zod_utilz
: Rahmen Agnostische Dienstprogramme für Zod.zod-playground
: Ein Werkzeug zum Lernen und Testen von ZOD-Schema-Validierungsfunktionen. Link.zod-sandbox
: kontrollierte Umgebung zum Testen von ZOD-Schemata. Live -Demo.zod-dev
: Deaktiviert die ZOD-Laufzeit-Parsen in der Produktion bedingt.zod-accelerator
: Beschleunigt den Durchsatz von ZOD bis zu ~ 100x. TypeScript 4.5+!
Sie müssen den strict
Modus in Ihrem tsconfig.json
aktivieren. Dies ist eine bewährte Verfahren für alle Typenkriptprojekte.
// tsconfig.json
{
// ...
"compilerOptions" : {
// ...
"strict" : true
}
}
npm
(Knoten/Bun) npm install zod # npm
yarn add zod # yarn
bun add zod # bun
pnpm add zod # pnpm
Zod veröffentlicht auch eine Kanarische Version in jedem Komitee. So installieren Sie die Kanarie:
npm install zod@canary # npm
yarn add zod@canary # yarn
bun add zod@canary # bun
pnpm add zod@canary # pnpm
deno.land/x
(Deno)Im Gegensatz zum Knoten stützt sich Deno auf direkte URL -Importe anstelle eines Paketmanagers wie NPM. ZOD ist auf Deno.land/x erhältlich. Die neueste Version kann wie SO importiert werden:
import { z } from "https://deno.land/x/zod/mod.ts" ;
Sie können auch eine bestimmte Version angeben:
import { z } from "https://deno.land/x/[email protected]/mod.ts" ;
Der Rest dieses Readme geht davon aus, dass Sie NPM verwenden und direkt aus dem
"zod"
-Paket importieren.
Erstellen eines einfachen String -Schemas
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 }
Erstellen eines Objektschemas
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 bietet jetzt eine bequemere Möglichkeit, primitive Werte zu erzwingen.
const schema = z . coerce . string ( ) ;
schema . parse ( "tuna" ) ; // => "tuna"
schema . parse ( 12 ) ; // => "12"
Während des Parsing-Schritts wird die Eingabe durch die String()
-Funktion geleitet, die ein JavaScript-integriert ist, um Daten in Zeichenfolgen zu zwingen.
schema . parse ( 12 ) ; // => "12"
schema . parse ( true ) ; // => "true"
schema . parse ( undefined ) ; // => "undefined"
schema . parse ( null ) ; // => "null"
Das zurückgegebene Schema ist eine normale ZodString
-Instanz, sodass Sie alle String -Methoden verwenden können.
z . coerce . string ( ) . email ( ) . min ( 5 ) ;
Wie Zwang funktioniert
Alle primitiven Typen unterstützen Zwang. ZOD zwingt alle Eingänge mit den integrierten Konstruktoren: String(input)
, Number(input)
, new Date(input)
usw.
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)
HINWEIS - Boolesche Zwang mit z.coerce.boolean()
funktioniert möglicherweise nicht, wie Sie es erwarten. Jeder wahrheitsgemäße Wert wird zu true
gezwungen, und jeder falsy -Wert wird zu false
gezwungen.
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
Für mehr Kontrolle über die Zwangslogik erwägen Sie z.preprocess
oder z.pipe()
.
Literale Schemas repräsentieren einen wörtlichen Typ wie "hello world"
oder 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"
Derzeit gibt es keine Unterstützung für Dattelliterale in ZOD. Wenn Sie einen Anwendungsfall für diese Funktion haben, stellen Sie bitte ein Problem ein.
ZOD enthält eine Handvoll stringspezifischer Validierungen.
// 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 ( ) ;
In Validator.js finden Sie eine Reihe anderer nützlicher String -Validierungsfunktionen, die in Verbindung mit Verfeinerungen verwendet werden können.
Sie können einige gängige Fehlermeldungen beim Erstellen eines String -Schemas anpassen.
const name = z . string ( {
required_error : "Name is required" ,
invalid_type_error : "Name must be a string" ,
} ) ;
Bei Verwendung von Validierungsmethoden können Sie ein zusätzliches Argument übergeben, um eine benutzerdefinierte Fehlermeldung anzugeben.
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" } ) ;
Wie Sie vielleicht bemerkt haben, enthält die ZOD -Zeichenfolge einige Datum/Uhrzeitbezogene Validierungen. Diese Validierungen basieren regelmäßig, sodass sie nicht so streng wie eine vollständige Zeit-/Uhrzeitbibliothek sind. Sie sind jedoch sehr bequem, um die Benutzereingabe zu validieren.
Die z.string().datetime()
-Methode erzwingt ISO 8601; Der Standardwert ist keine Zeitzon-Offsets und eine willkürliche Dezimalpräzision unter Sekunde.
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)
Timezone -Offsets können zulässig sein, indem die Option offset
-Option auf true
festgelegt wird.
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)
Sie können die zulässige precision
zusätzlich einschränken. Standardmäßig wird eine willkürliche Präzision unter sekundenreicher (aber optional) unterstützt.
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
In ZOD 3.23 hinzugefügt
Die z.string().date()
-Methode validiert die Zeichenfolgen im 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
In ZOD 3.23 hinzugefügt
Die z.string().time()
-Methode validiert Zeichenfolgen im Format HH:MM:SS[.s+]
. Der zweite kann willkürliche Dezimalpräzision umfassen. Es erlaubt keine Zeitzone -Offsets jeglicher Art.
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)
Sie können die precision
festlegen, um die zulässige Dezimalgenauigkeit einzuschränken.
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
Die z.string().ip()
-Methode validieren standardmäßig IPv4 und 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
Sie können die IP version
zusätzlich festlegen.
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
Sie können bestimmte Fehlermeldungen beim Erstellen eines Zahlenschemas anpassen.
const age = z . number ( {
required_error : "Age is required" ,
invalid_type_error : "Age must be a number" ,
} ) ;
ZOD enthält eine Handvoll zahlenspezifischer Validierungen.
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
Optional können Sie ein zweites Argument übergeben, um eine benutzerdefinierte Fehlermeldung anzugeben.
z . number ( ) . lte ( 5 , { message : "this?is?too?big" } ) ;
ZOD enthält eine Handvoll Bigint-spezifischer Validierungen.
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.
Sie können bestimmte Fehlermeldungen beim Erstellen eines NAN -Schemas anpassen.
const isNaN = z . nan ( {
required_error : "isNaN is required" ,
invalid_type_error : "isNaN must be 'not a number'" ,
} ) ;
Sie können bestimmte Fehlermeldungen beim Erstellen eines booleschen Schemas anpassen.
const isActive = z . boolean ( {
required_error : "isActive is required" ,
invalid_type_error : "isActive must be a boolean" ,
} ) ;
Verwenden Sie Z.Date (), um Date
zu validieren.
z . date ( ) . safeParse ( new Date ( ) ) ; // success: true
z . date ( ) . safeParse ( "2022-01-12T00:00:00.000Z" ) ; // success: false
Sie können bestimmte Fehlermeldungen beim Erstellen eines Datumsschemas anpassen.
const myDateSchema = z . date ( {
required_error : "Please select a date and time" ,
invalid_type_error : "That's not a date!" ,
} ) ;
ZOD bietet eine Handvoll von Datumsspezifischen Validierungen.
z . date ( ) . min ( new Date ( "1900-01-01" ) , { message : "Too old" } ) ;
z . date ( ) . max ( new Date ( ) , { message : "Too young!" } ) ;
Zwang bis heute
Seit ZOD 3.20 verwenden Sie z.coerce.date()
um die Eingabe über new Date(input)
zu übergeben.
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
Verwenden Sie für ältere ZOD -Versionen z.preprocess
, wie in diesem Thread beschrieben.
const FishEnum = z . enum ( [ "Salmon" , "Tuna" , "Trout" ] ) ;
type FishEnum = z . infer < typeof FishEnum > ;
// 'Salmon' | 'Tuna' | 'Trout'
z.enum
ist eine zod-native Möglichkeit, ein Schema mit einem festen Satz zulässiger Stringwerte zu deklarieren. Geben Sie das Wertearray direkt in z.enum()
über. Verwenden Sie alternativ as const
, um Ihre Enum -Werte als ein Tupel von Strings zu definieren. Weitere Informationen finden Sie in den Dokumenten der Const Assertion.
const VALUES = [ "Salmon" , "Tuna" , "Trout" ] as const ;
const FishEnum = z . enum ( VALUES ) ;
Dies ist nicht erlaubt, da Zod nicht in der Lage ist, die genauen Werte jedes Elements zu schließen.
const fish = [ "Salmon" , "Tuna" , "Trout" ] ;
const FishEnum = z . enum ( fish ) ;
.enum
Verwenden Sie die .enum
-Eigenschaft Ihres Schemas:
FishEnum . enum . Salmon ; // => autocompletes
FishEnum . enum ;
/*
=> {
Salmon: "Salmon",
Tuna: "Tuna",
Trout: "Trout",
}
*/
Sie können auch die Liste der Optionen als Tupel mit der Eigenschaft .options
abrufen:
FishEnum . options ; // ["Salmon", "Tuna", "Trout"];
.exclude/.extract()
Sie können Teilmengen eines ZOD -Enum mit den .exclude
und .extract
-Methoden erstellen.
const FishEnum = z . enum ( [ "Salmon" , "Tuna" , "Trout" ] ) ;
const SalmonAndTrout = FishEnum . extract ( [ "Salmon" , "Trout" ] ) ;
const TunaOnly = FishEnum . exclude ( [ "Salmon" , "Trout" ] ) ;
Zod Enums sind der empfohlene Ansatz zur Definition und Validierung von Enums. Wenn Sie jedoch gegen eine Enum aus einer Drittanbieterbibliothek (oder nicht Ihre vorhandenen Umzüge umschreiben möchten) validieren müssen, können Sie z.nativeEnum()
verwenden.
Numerische Aufzüge
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 -Aufenthalt
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
Die .nativeEnum()
-Funktion funktioniert auch as const
-Objekte.as const
erfordert 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
Sie können mit der Eigenschaft .enum
auf das zugrunde liegende Objekt zugreifen:
FruitEnum . enum . Apple ; // "apple"
Sie können jedes Schema mit z.optional()
optional machen. Dadurch wickelt das Schema in eine ZodOptional
und gibt das Ergebnis zurück.
const schema = z . optional ( z . string ( ) ) ;
schema . parse ( undefined ) ; // => returns undefined
type A = z . infer < typeof schema > ; // string | undefined
Aus Gründen der Einschätzung können Sie auch die .optional()
-Methode auf einem vorhandenen Schema aufrufen.
const user = z . object ( {
username : z . string ( ) . optional ( ) ,
} ) ;
type C = z . infer < typeof user > ; // { username?: string | undefined };
Sie können das eingewickelte Schema aus einer ZodOptional
Instanz mit .unwrap()
extrahieren.
const stringSchema = z . string ( ) ;
const optionalString = stringSchema . optional ( ) ;
optionalString . unwrap ( ) === stringSchema ; // true
In ähnlicher Weise können Sie mit z.nullable()
nullbare Typen erstellen.
const nullableString = z . nullable ( z . string ( ) ) ;
nullableString . parse ( "asdf" ) ; // => "asdf"
nullableString . parse ( null ) ; // => null
Oder verwenden Sie die Methode .nullable()
.
const E = z . string ( ) . nullable ( ) ; // equivalent to nullableString
type E = z . infer < typeof E > ; // string | null
Extrahieren Sie das innere Schema mit .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
Verwenden Sie .shape
, um auf die Schemas für einen bestimmten Schlüssel zuzugreifen.
Dog . shape . name ; // => string schema
Dog . shape . age ; // => number schema
.keyof
Verwenden Sie .keyof
, um ein ZodEnum
-Schema aus den Schlüssel eines Objektschemas zu erstellen.
const keySchema = Dog . keyof ( ) ;
keySchema ; // ZodEnum<["name", "age"]>
.extend
Sie können einem Objektschema zusätzliche Felder mit der .extend
-Methode hinzufügen.
const DogWithBreed = Dog . extend ( {
breed : z . string ( ) ,
} ) ;
Sie können .extend
verwenden, um Felder zu überschreiben! Sei vorsichtig mit dieser Kraft!
.merge
Äquivalent zu 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 }
Wenn die beiden Schemas Tasten teilen, übertreibt die Eigenschaften von B die Eigenschaft von A. Das zurückgegebene Schema erbt auch die Richtlinie "UnbekannteKeys" (Strict/Strict/Passthrough) und das Catchall -Schema von B.
.pick/.omit
Inspiriert von den Pick
Dienstprogrammtypen von TypeScript haben alle ZOD Omit
Objektschemas .pick
und .omit
Methoden, die eine modifizierte Version zurückgeben. Betrachten Sie dieses Rezeptschema:
const Recipe = z . object ( {
id : z . string ( ) ,
name : z . string ( ) ,
ingredients : z . array ( z . string ( ) ) ,
} ) ;
Um nur bestimmte Schlüssel zu behalten, verwenden Sie .pick
.
const JustTheName = Recipe . pick ( { name : true } ) ;
type JustTheName = z . infer < typeof JustTheName > ;
// => { name: string }
Verwenden Sie, um bestimmte Schlüssel zu entfernen, und verwenden Sie .omit
.
const NoIDRecipe = Recipe . omit ( { id : true } ) ;
type NoIDRecipe = z . infer < typeof NoIDRecipe > ;
// => { name: string, ingredients: string[] }
.partial
Inspiriert von dem integrierten Typenkripttyp teilweises. Die .partial
Methode macht alle Eigenschaften optional.
Ausgehend von diesem Objekt:
const user = z . object ( {
email : z . string ( ) ,
username : z . string ( ) ,
} ) ;
// { email: string; username: string }
Wir können eine Teilversion erstellen:
const partialUser = user . partial ( ) ;
// { email?: string | undefined; username?: string | undefined }
Sie können auch angeben, welche Eigenschaften optional sind:
const optionalEmail = user . partial ( {
email : true ,
} ) ;
/*
{
email?: string | undefined;
username: string
}
*/
.deepPartial
Die .partial
Methode ist flach - sie wendet nur eine Ebene tief an. Es gibt auch eine "tiefe" Version:
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}[]
}
*/
Wichtige Einschränkung: Tiefe Teilungen funktionieren nur wie in Hierarchien von Objekten, Arrays und Tupeln erwartet.
.required
Im Gegensatz zur .partial
Methode macht die. .required
Methode alle Eigenschaften erforderlich.
Ausgehend von diesem Objekt:
const user = z
. object ( {
email : z . string ( ) ,
username : z . string ( ) ,
} )
. partial ( ) ;
// { email?: string | undefined; username?: string | undefined }
Wir können eine erforderliche Version erstellen:
const requiredUser = user . required ( ) ;
// { email: string; username: string }
Sie können auch angeben, welche Eigenschaften erforderlich sind:
const requiredEmail = user . required ( {
email : true ,
} ) ;
/*
{
email: string;
username?: string | undefined;
}
*/
.passthrough
Standardmäßig zeichnen ZOD -Objektschemas unerkannte Schlüssel während der Parsen aus.
const person = z . object ( {
name : z . string ( ) ,
} ) ;
person . parse ( {
name : "bob dylan" ,
extraKey : 61 ,
} ) ;
// => { name: "bob dylan" }
// extraKey has been stripped
Wenn Sie stattdessen unbekannte Schlüssel durchlaufen möchten, verwenden Sie .passthrough()
.
person . passthrough ( ) . parse ( {
name : "bob dylan" ,
extraKey : 61 ,
} ) ;
// => { name: "bob dylan", extraKey: 61 }
.strict
Standardmäßig zeichnen ZOD -Objektschemas unerkannte Schlüssel während der Parsen aus. Sie können unbekannte Schlüssel mit .strict()
nicht zulassen . Wenn der Eingang unbekannte Schlüssel enthält, wirft ZOD einen Fehler auf.
const person = z
. object ( {
name : z . string ( ) ,
} )
. strict ( ) ;
person . parse ( {
name : "bob dylan" ,
extraKey : 61 ,
} ) ;
// => throws ZodError
.strip
Sie können die .strip
-Methode verwenden, um ein Objektschema auf das Standardverhalten zurückzusetzen (nicht anerkannte Schlüssel).
.catchall
Sie können ein "Catchall" -Schema in ein Objektschema übergeben. Alle unbekannten Schlüssel werden dagegen validiert.
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
Mit .catchall()
vermeidet .passthrough()
, .strip()
oder .strict()
. Alle Schlüssel gelten jetzt als "bekannt".
const stringArray = z . array ( z . string ( ) ) ;
// equivalent
const stringArray = z . string ( ) . array ( ) ;
Seien Sie vorsichtig mit der Methode .array()
. Es gibt eine neue ZodArray
-Instanz zurück. Dies bedeutet die Reihenfolge , in der Sie Methoden anrufen. Zum Beispiel:
z . string ( ) . optional ( ) . array ( ) ; // (string | undefined)[]
z . string ( ) . array ( ) . optional ( ) ; // string[] | undefined
.element
Verwenden Sie .element
um auf das Schema für ein Element des Arrays zuzugreifen.
stringArray . element ; // => string schema
.nonempty
Wenn Sie sicherstellen möchten, dass ein Array mindestens ein Element enthält, verwenden Sie .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
Sie können optional eine benutzerdefinierte Fehlermeldung angeben:
// 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
Im Gegensatz zu .nonempty()
ändern diese Methoden den abgeleiteten Typ nicht.
Im Gegensatz zu Arrays haben Tupel eine feste Anzahl von Elementen und jedes Element kann einen anderen Typ haben.
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 }]
Ein variadisches Argument ("Rest") kann mit der .rest
-Methode hinzugefügt werden.
const variadicTuple = z . tuple ( [ z . string ( ) ] ) . rest ( z . number ( ) ) ;
const result = variadicTuple . parse ( [ "hello" , 1 , 2 , 3 ] ) ;
// => [string, ...number[]];
ZOD enthält eine eingebaute z.union
-Methode zum Komponieren "oder" Typen.
const stringOrNumber = z . union ( [ z . string ( ) , z . number ( ) ] ) ;
stringOrNumber . parse ( "foo" ) ; // passes
stringOrNumber . parse ( 14 ) ; // passes
ZOD testet die Eingabe gegen jede der "Optionen" in der Reihenfolge und gibt den ersten Wert zurück, der erfolgreich validiert.
Zur Bequemlichkeit können Sie auch die .or
-Methode verwenden:
const stringOrNumber = z . string ( ) . or ( z . number ( ) ) ;
Optionale Zeichenfolge Validierung:
Um einen optionalen Formulareingang zu validieren, können Sie die gewünschte Zeichenfolgevalidierung mit einem leeren String -Literal vereinen.
Dieses Beispiel bestätigt eine optionale Eingabe, die jedoch eine gültige URL enthalten muss:
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
Eine diskriminierte Gewerkschaft ist eine Vereinigung von Objektschemata, die alle einen bestimmten Schlüssel teilen.
type MyUnion =
| { status : "success" ; data : string }
| { status : "failed" ; error : Error } ;
Solche Gewerkschaften können mit der z.discriminatedUnion
Methode dargestellt werden. Dies ermöglicht eine schnellere Bewertung, da ZOD den Diskriminatorschlüssel ( status
im obigen Beispiel) überprüfen kann, um zu bestimmen, welches Schema zur Analyse der Eingabe verwendet werden sollte. Dadurch wird das Parsen effizienter und lässt ZOD freundlichere Fehler melden.
Mit der grundlegenden Gewerkschaftsmethode wird die Eingabe gegen jede der bereitgestellten "Optionen" getestet, und bei Ungültigkeit werden Probleme für alle "Optionen" im ZOD -Fehler angezeigt. Andererseits ermöglicht die diskriminierte Gewerkschaft die Auswahl nur eines der "Optionen", das Testen dagegen und nur die Probleme, die mit dieser "Option" im Zusammenhang mit dieser "Option" angezeigt werden.
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" } ) ;
Sie können einen Verweis auf das Array der Schemas mit der Eigenschaft .options
-Eigenschaft extrahieren.
myUnion . options ; // [ZodObject<...>, ZodObject<...>]
Um zwei oder mehr diskriminierte Gewerkschaften zusammenzuführen, verwenden Sie .options
mit Zerstörungen.
const A = z . discriminatedUnion ( "status" , [
/* options */
] ) ;
const B = z . discriminatedUnion ( "status" , [
/* options */
] ) ;
const AB = z . discriminatedUnion ( "status" , [ ... A . options , ... B . options ] ) ;
Datensatzschemata werden verwendet, um Typen wie z. B. Record<string, number>
zu validieren. Dies ist besonders nützlich, um Elemente nach ID zu speichern oder zu zwischenstrahlen.
const User = z . object ( { name : z . string ( ) } ) ;
const UserStore = z . record ( z . string ( ) , User ) ;
type UserStore = z . infer < typeof UserStore > ;
// => Record<string, { name: string }>
Das Schema und der abgeleitete Typ können so verwendet werden:
const userStore : UserStore = { } ;
userStore [ "77d2586b-9e8e-4ecf-8b21-ea7e0530eadd" ] = {
name : "Carlotta" ,
} ; // passes
userStore [ "77d2586b-9e8e-4ecf-8b21-ea7e0530eadd" ] = {
whatever : "Ice cream sundae" ,
} ; // TypeError
Eine Notiz zu numerischen Schlüssel
Während z.record(keyType, valueType)
numerische Schlüsseltypen akzeptieren kann und der integrierte Datensatztyp von TypeScript ist Record<KeyType, ValueType>
, es ist schwierig, den Typscript-Typ- Record<number, any>
zn.
Wie sich herausstellt, ist das Verhalten von TypeScript um [k: number]
etwas unintuitiv:
const testMap : { [ k : number ] : string } = {
1 : "one" ,
} ;
for ( const key in testMap ) {
console . log ( ` ${ key } : ${ typeof key } ` ) ;
}
// prints: `1: string`
Wie Sie sehen können, leitet JavaScript automatisch alle Objektschlüssel in Zeichenfolgen unter die Motorhaube. Da Zod versucht, die Lücke zwischen statischen und Laufzeittypen zu überbrücken, ist es nicht sinnvoll, ein Rekordschema mit numerischen Schlüssel zu erstellen, da es keinen numerischen Schlüssel in der Laufzeit -JavaScript gibt.
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 -Schemata können mit den folgenden Nutzmethoden weiter eingeschränkt werden.
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
Kreuzungen sind nützlich, um "logische und" Typen zu erstellen. Dies ist nützlich, um zwei Objekttypen zu überschneiden.
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 ) ;
In vielen Fällen wird empfohlen, A.merge(B)
zu verwenden, um zwei Objekte zu verschmelzen. Die .merge
-Methode gibt eine neue ZodObject
-Instanz zurück, während A.and(B)
eine weniger nützliche ZodIntersection
zurückgibt, die keine gängigen Objektmethoden wie pick
und omit
gibt.
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
Sie können ein rekursives Schema in ZOD definieren, aber aufgrund einer Einschränkung des Typenskripts kann ihr Typ nicht statisch abgeleitet werden. Stattdessen müssen Sie die Typdefinition manuell definieren und ZOD als "Typ Hinweis" zur Verfügung stellen.
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
Vielen Dank an Crasit für dieses Beispiel.
Bei Verwendung z.ZodType
mit z.ZodEffects
( .refine
, .transform
, preprocess
usw.) müssen Sie die Eingangs- und Ausgangstypen des Schemas definieren. 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 ( ) ) ,
} ) ;
Vielen Dank an Marcus13371337 und Joelbeeldi für dieses Beispiel.
Wenn Sie einen JSON -Wert validieren möchten, können Sie den folgenden Snippet verwenden.
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 ) ;
Vielen Dank an Ggoodman, dass Sie dies vorgeschlagen haben.
Trotz der Unterstützung von rekursiven Schemas führt die Übergabe von zyklischen Daten in ZOD in einigen Fällen zu einer unendlichen Schleife.
Betrachten Sie diesen Ansatz, um zyklische Objekte zu erkennen, bevor sie Probleme verursachen.
const numberPromise = z . promise ( z . number ( ) ) ;
"Parsen" funktioniert ein wenig anders mit Versprechenschemata. Validierung erfolgt in zwei Teilen:
.then
und .catch
-Methoden)..then
um dem vorhandenen Versprechen einen zusätzlichen Validierungsschritt beizubringen. Sie müssen das zurückgegebene Versprechen verwenden .catch
um Validierungsfehler zu behandeln. 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
} ;
Sie können z.instanceof
verwenden, um zu überprüfen, ob die Eingabe eine Instanz einer Klasse ist. Dies ist nützlich, um Eingaben gegen Klassen zu validieren, die aus Bibliotheken von Drittanbietern exportiert werden.
class Test {
name : string ;
}
const TestSchema = z . instanceof ( Test ) ;
const blob : any = "whatever" ;
TestSchema . parse ( new Test ( ) ) ; // passes
TestSchema . parse ( blob ) ; // throws
Mit Zod können Sie auch "Funktionsschemas" definieren. Auf diese Weise können Sie die Eingänge und Ausgaben einer Funktion leicht validieren, ohne Ihren Validierungscode und "Geschäftslogik" zu vermischen.
Sie können ein Funktionsschema mit z.function(args, returnType)
erstellen.
const myFunction = z . function ( ) ;
type myFunction = z . infer < typeof myFunction > ;
// => ()=>unknown
Definieren Sie Eingänge und Ausgänge.
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
Funktionsschemas haben eine .implement()
-Methode, die eine Funktion akzeptiert und eine neue Funktion zurückgibt, die die Eingaben und Ausgänge automatisch validiert.
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
Wenn Sie sich nur für die Validierung von Eingaben interessieren, rufen Sie einfach nicht die .returns()
-Methode auf. Der Ausgangstyp wird aus der Implementierung abgeleitet.
Sie können die spezielle Option
z.void()
verwenden, wenn Ihre Funktion nichts zurückgibt. Dadurch kann Zod die Art der Void-Rückkehrfunktionen richtig schließen. (Leerlauffunktionen kehren tatsächlich undefiniert zurück.)
const myFunction = z
. function ( )
. args ( z . string ( ) )
. implement ( ( arg ) => {
return [ arg . length ] ;
} ) ;
myFunction ; // (arg: string)=>number[]
Extrahieren Sie die Eingangs- und Ausgangsschemata aus einem Funktionsschema.
myFunction . parameters ( ) ;
// => ZodTuple<[ZodString, ZodNumber]>
myFunction . returnType ( ) ;
// => ZodBoolean
Zod unterstützt nun primitive Zwang, ohne dass
.preprocess()
. Weitere Informationen finden Sie im Zwangsdocs.
Typischerweise arbeitet Zod unter einem Paradigma "Parse dann transformieren". ZOD validiert zuerst die Eingabe und führt sie dann durch eine Kette von Transformationsfunktionen durch. (Weitere Informationen zu Transformationen finden Sie in den Dokumenten.)
Aber manchmal möchten Sie vor dem Parsen eine gewisse Transformation in die Eingabe anwenden. Ein allgemeiner Anwendungsfall: Typ -Zwang. ZOD ermöglicht dies mit dem z.preprocess()
.
const castToString = z . preprocess ( ( val ) => String ( val ) , z . string ( ) ) ;
Dies gibt eine ZodEffects
-Instanz zurück. ZodEffects
ist eine Wrapper -Klasse, die alle Logik für Vorverarbeitung, Verfeinerungen und Transformationen enthält.
Sie können ein ZOD -Schema für jeden TypeScript -Typ erstellen, indem Sie z.custom()
verwenden. Dies ist nützlich, um Schemata für Typen zu erstellen, die nicht von ZOD nicht unterstützt werden, wie z.
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;
Wenn Sie keine Validierungsfunktion angeben, erlaubt ZOD einen Wert. Das kann gefährlich sein!
z . custom < { arg : string } > ( ) ; // performs no validation
Sie können die Fehlermeldung und andere Optionen anpassen, indem Sie ein zweites Argument übergeben. Dieser Parameter funktioniert genauso wie der Parameter Parameter von .refine
.
z . custom < ... > ( ( val ) => ... , "custom error message" ) ;
Alle ZOD -Schemata enthalten bestimmte Methoden.
.parse
.parse(data: unknown): T
Angesichts eines ZOD -Schemas können Sie die .parse
-Methode aufrufen, um data
zu überprüfen, die gültig sind. Wenn dies der Fall ist, wird ein Wert mit vollständigen Typinformationen zurückgegeben! Andernfalls wird ein Fehler geworfen.
WICHTIG: Der von
.parse
zurückgegebene Wert ist ein tiefer Klon der Variablen, die Sie übergeben haben.
const stringSchema = z . string ( ) ;
stringSchema . parse ( "fish" ) ; // => returns "fish"
stringSchema . parse ( 12 ) ; // throws error
.parseAsync
.parseAsync(data:unknown): Promise<T>
Wenn Sie asynchrone Verfeinerungen oder Transformationen verwenden (mehr zu diesen später), müssen Sie .parseAsync
verwenden.
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; }
Wenn Sie nicht möchten, dass ZOD bei Ausfall der Validierung Fehler wirft, verwenden Sie .safeParse
. Diese Methode gibt ein Objekt zurück, das entweder die erfolgreich analysierten Daten oder eine Zoderrorinstanz enthält, die detaillierte Informationen über die Validierungsprobleme enthält.
stringSchema . safeParse ( 12 ) ;
// => { success: false; error: ZodError }
stringSchema . safeParse ( "billie" ) ;
// => { success: true; data: 'billie' }
Das Ergebnis ist eine diskriminierte Gewerkschaft , sodass Sie sehr bequem Fehler bewältigen können:
const result = stringSchema . safeParse ( "billie" ) ;
if ( ! result . success ) {
// handle error then return
result . error ;
} else {
// do something
result . data ;
}
.safeParseAsync
Alias:
.spa
Eine asynchrone Version von safeParse
.
await stringSchema . safeParseAsync ( "billie" ) ;
Aus Gründen der Bequemlichkeit wurde dies auf .spa
gewandt:
await stringSchema . spa ( "billie" ) ;
.refine
.refine(validator: (data:T)=>any, params?: RefineParams)
Mit Zod können Sie durch Verfeinerungen eine benutzerdefinierte Validierungslogik bereitstellen. (Für erweiterte Funktionen wie das Erstellen mehrerer Probleme und das Anpassen von .superRefine
finden Sie unter.
ZOD wurde so konzipiert, dass das Typenkript so genau wie möglich spiegelt. Es gibt jedoch viele sogenannte "Verfeinerungstypen", die Sie möglicherweise überprüfen möchten, die im TypeScript-Typ-System nicht dargestellt werden können. Zum Beispiel: Überprüfen Sie, ob eine Nummer eine Ganzzahl ist oder dass eine Zeichenfolge eine gültige E -Mail -Adresse ist.
Beispielsweise können Sie eine benutzerdefinierte Validierungsprüfung für jedes ZOD -Schema mit .refine
definieren:
const myString = z . string ( ) . refine ( ( val ) => val . length <= 255 , {
message : "String can't be more than 255 characters" ,
} ) ;
Euen Verfeinerungsfunktionen sollten nicht werfen. Stattdessen sollten sie einen falsy -Wert auf Signalversagen zurückgeben.
Wie Sie sehen können, nimmt .refine
zwei Argumente.
T
- den abgeleiteten Typ des Schemas) und gibt any
zurück. Jeder wahrheitsgemäße Wert wird die Validierung bestehen. (Vor [email protected] musste die Validierungsfunktion einen Booleschen zurückgeben.) 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 ;
} ;
Für fortgeschrittene Fälle kann das zweite Argument auch eine Funktion sein, die RefineParams
zurückgibt.
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" } ) ;
Da Sie einen path
angegeben haben, ist der resultierende Fehler:
ZodError {
issues : [ {
"code" : "custom" ,
"path" : [ "confirm" ] ,
"message" : "Passwords don't match"
} ]
}
Verfeinerungen können auch asynchronisiert werden:
const userId = z . string ( ) . refine ( async ( id ) => {
// verify that ID exists in database
return true ;
} ) ;
Euen Wenn Sie asynchronisierte Verfeinerungen verwenden, müssen Sie die.parseAsync
-Methode verwenden, um Daten zu analysieren! Andernfalls wirft ZOD einen Fehler.
Transformationen und Verfeinerungen können verschachtelt werden:
z . string ( )
. transform ( ( val ) => val . length )
. refine ( ( val ) => val > 25 ) ;
.superRefine
Die .refine
-Methode ist tatsächlich syntaktischer Zucker auf einer vielseitigeren (und ausführlichen) Methode, die als superRefine
bezeichnet wird. Hier ist ein Beispiel:
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.` ,
} ) ;
}
} ) ;
Sie können so viele Probleme hinzufügen, wie Sie möchten. Wenn ctx.addIssue
während der Ausführung der Funktion nicht aufgerufen wird, wird die Validierung erfolgt.
Normalerweise erzeugen Verfeinerungen immer Probleme mit einem ZodIssueCode.custom
-Fehlercode, aber mit superRefine
ist es möglich, Probleme mit ZodIssueCode
zu werfen. Jeder Ausgabescode wird im Fehlerbehandlungshandbuch ausführlich beschrieben: IRRAUS_HANDLING.MD.
Standardmäßig wird die Parsen auch nach Fehlschlägen eines Verfeinerungsprüfers fortgesetzt. Wenn Sie beispielsweise mehrere Verfeinerungen anketten, werden alle ausgeführt. Es kann jedoch wünschenswert sein , frühzeitig abzubrechen, um zu verhindern, dass spätere Verfeinerungen ausgeführt werden. Um dies zu erreichen, übergeben Sie die fatal
Flagge an ctx.addIssue
und geben Sie z.NEVER
zurück.
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" ,
} ) ;
}
} ) ;
Wenn Sie .refine()
oder .superRefine()
ein Typ -Prädikat angeben, wird der resultierende Typ auf den Typ Ihres Prädikats eingeschränkt. Dies ist nützlich, wenn Sie mehrere verkettete Verfeinerungen und Transformationen mischen:
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`!" ) ;
Euen Sie müssenctx.addIssue()
verwenden, anstatt einen booleschen Wert zurückzugeben, um anzugeben, ob die Validierung passt. Wennctx.addIssue
während der Ausführung der Funktion nicht aufgerufen wird, wird die Validierung erfolgt.
.transform
Verwenden Sie zur Transformation von Daten nach der Parsen die transform
.
const stringToNumber = z . string ( ) . transform ( ( val ) => val . length ) ;
stringToNumber . parse ( "string" ) ; // => 6
Beachten Sie, dass stringToNumber
oben eine Instanz der ZodEffects
-Unterklasse ist. Es ist kein Beispiel von ZodString
. Wenn Sie die integrierten Methoden von ZodString
(z. B. EG .email()
) verwenden möchten, müssen Sie diese Methoden vor Transformationen anwenden.
const emailToDomain = z
. string ( )
. email ( )
. transform ( ( val ) => val . split ( "@" ) [ 1 ] ) ;
emailToDomain . parse ( "[email protected]" ) ; // => example.com
Die .transform
-Methode kann den Wert gleichzeitig validieren und transformieren. Dies ist oft einfacher und weniger doppelt als die transform
und refine
.
Wie bei .superRefine
empfängt die Transformationsfunktion ein ctx
-Objekt mit einer addIssue
-Methode, mit der Validierungsprobleme registriert werden können.
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 ;
} ) ;
Transformationen und Verfeinerungen können verschachtelt werden. Diese werden in der Reihenfolge ausgeführt, die sie deklariert werden.
const nameToGreeting = z
. string ( )
. transform ( ( val ) => val . toUpperCase ( ) )
. refine ( ( val ) => val . length > 15 )
. transform ( ( val ) => `Hello ${ val } ` )
. refine ( ( val ) => val . indexOf ( "!" ) === - 1 ) ;
Transformationen können auch asynchronisiert werden.
const IdToUser = z
. string ( )
. uuid ( )
. transform ( async ( id ) => {
return await getUserById ( id ) ;
} ) ;
Euen Wenn Ihr Schema asynchrone Transformationen enthält, müssen Sie .Parseasync () oder .SafeParSeasync () verwenden, um Daten zu analysieren. Andernfalls wirft ZOD einen Fehler.
.default
Sie können Transformationen verwenden, um das Konzept der "Standardwerte" in ZOD zu implementieren.
const stringWithDefault = z . string ( ) . default ( "tuna" ) ;
stringWithDefault . parse ( undefined ) ; // => "tuna"
Optional können Sie eine Funktion in .default
übergeben, die erneut ausgeführt wird, wenn ein Standardwert generiert werden muss:
const numberWithRandomDefault = z . number ( ) . default ( Math . random ) ;
numberWithRandomDefault . parse ( undefined ) ; // => 0.4413456736055323
numberWithRandomDefault . parse ( undefined ) ; // => 0.1871840107401901
numberWithRandomDefault . parse ( undefined ) ; // => 0.7223408162401552
Konzeptionell verarbeitet ZOD Standardwerte:
undefined
ist, wird der Standardwert zurückgegeben.describe
Verwenden Sie .describe()
um dem resultierenden Schema eine description
hinzuzufügen.
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…
Dies kann nützlich sein, um ein Feld zu dokumentieren, beispielsweise in einem JSON-Schema mit einer Bibliothek wie zod-to-json-schema
).
.catch
Verwenden Sie .catch()
um einen "Catch -Wert" bereitzustellen, der im Falle eines Parsenfehlers zurückgegeben werden soll.
const numberWithCatch = z . number ( ) . catch ( 42 ) ;
numberWithCatch . parse ( 5 ) ; // => 5
numberWithCatch . parse ( "tuna" ) ; // => 42
Optional können Sie eine Funktion in .catch
übergeben, die erneut ausgeführt wird, wenn ein Standardwert generiert werden muss. Ein ctx
-Objekt, das den gefangenen Fehler enthält, wird in diese Funktion übergeben.
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
Konzeptionell verarbeitet ZOD "Werte fangen":
.optional
Eine Convenience -Methode, die eine optionale Version eines Schemas zurückgibt.
const optionalString = z . string ( ) . optional ( ) ; // string | undefined
// equivalent to
z . optional ( z . string ( ) ) ;
.nullable
Eine Convenience -Methode, die eine nullbare Version eines Schemas zurückgibt.
const nullableString = z . string ( ) . nullable ( ) ; // string | null
// equivalent to
z . nullable ( z . string ( ) ) ;
.nullish
Eine Convenience -Methode, die eine "nullische" Version eines Schemas zurückgibt. Nullish -Schemata akzeptieren sowohl undefined
als auch null
. Lesen Sie mehr über das Konzept von "Nullish" in den Versionshinweise "TypeScript 3.7".
const nullishString = z . string ( ) . nullish ( ) ; // string | null | undefined
// equivalent to
z . string ( ) . nullable ( ) . optional ( ) ;
.array
Eine Komfortmethode, die ein Array -Schema für den angegebenen Typ zurückgibt:
const stringArray = z . string ( ) . array ( ) ; // string[]
// equivalent to
z . array ( z . string ( ) ) ;
.promise
Eine Convenience -Methode für Versprechensarten:
const stringPromise = z . string ( ) . promise ( ) ; // Promise<string>
// equivalent to
z . promise ( z . string ( ) ) ;
.or
Eine Komfortmethode für Gewerkschaftstypen.
const stringOrNumber = z . string ( ) . or ( z . number ( ) ) ; // string | number
// equivalent to
z . union ( [ z . string ( ) , z . number ( ) ] ) ;
.and
Eine Komfortmethode zum Erstellen von Schnitttypen.
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>
Das Typ -System von TypeScript ist strukturell, was bedeutet, dass zwei strukturell äquivalent angesehene Arten als gleich sind.
type Cat = { name : string } ;
type Dog = { name : string } ;
const petCat = ( cat : Cat ) => { } ;
const fido : Dog = { name : "fido" } ;
petCat ( fido ) ; // works fine
In einigen Fällen kann es wünschenswert sein, dass die nominale Typisierung innerhalb von TypeScript simuliert wird. Zum Beispiel möchten Sie möglicherweise eine Funktion schreiben, die nur eine von ZOD validierte Eingabe akzeptiert. Dies kann mit Markentypen (auch bekannt als undurchsichtige Typen ) erreicht werden.
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" } ) ;
Unter der Motorhaube wird mithilfe eines Kreuzungsarts eine "Marke" an den abgeleiteten Typ angeschlossen. Auf diese Weise sind einfache/ungebrandige Datenstrukturen nicht mehr dem abgeleiteten Typ des Schemas zugeordnet.
const Cat = z . object ( { name : z . string ( ) } ) . brand < "Cat" > ( ) ;
type Cat = z . infer < typeof Cat > ;
// {name: string} & {[symbol]: "Cat"}
Beachten Sie, dass Markentypen das Laufzeitergebnis von .parse
nicht beeinflussen. Es ist ein statisches Konstrukt.
.readonly
.readonly() => ZodReadonly<this>
Diese Methode gibt eine ZodReadonly
-Schema -Instanz zurück, die die Eingabe mithilfe des Basisschemas analysiert und dann Object.freeze()
für das Ergebnis nennt. Der abgeleitete Typ ist auch als readonly
markiert.
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
Der abgeleitete Typ verwendet bei relevanten integrierten Readonly-Typen die integrierten TypeScript-Typen.
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
Schemata können in die Validierung "Pipelines" gekettet werden. Es ist nützlich, um das Ergebnis nach einem .transform()
leicht zu validieren:
z . string ( )
. transform ( ( val ) => val . length )
. pipe ( z . number ( ) . min ( 5 ) ) ;
Die Methode .pipe()
gibt eine ZodPipeline
-Instanz zurück.
.pipe()
verwenden, um gemeinsame Probleme mit z.coerce
zu beheben. Sie können die Eingabe auf Typen einschränken, die gut mit Ihrem gewählten Zwang funktionieren. Verwenden Sie dann .pipe()
um den Zwang anzuwenden.
ohne eingeschränkte Eingabe:
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
mit eingeschränkter Eingabe:
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
Sie können diese Technik auch verwenden, um Zwang zu vermeiden, die ungewöhnliche Fehler werfen.
ohne eingeschränkte Eingabe:
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
mit eingeschränkter Eingabe:
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
Sie können den TypeScript -Typ eines beliebigen Schemas mit z.infer<typeof mySchema>
extrahieren.
const A = z . string ( ) ;
type A = z . infer < typeof A > ; // string
const u : A = 12 ; // TypeError
const u : A = "asdf" ; // compiles
Was ist mit Transformationen?
In der Realität verfolgt jedes ZOD -Schema zwei Typen intern: ein Eingang und eine Ausgabe. Für die meisten Schemata (z. B. z.string()
) sind diese beiden gleich. Sobald Sie jedoch Transformationen in die Mischung hinzufügen, können diese beiden Werte abweichen. Zum Beispiel z.string().transform(val => val.length)
hat eine Eingabe der string
und einen Ausgang der number
.
Sie können die Eingangs- und Ausgangstypen wie SO separat extrahieren:
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
Mit TypeScript -Generika können Sie wiederverwendbare Funktionen schreiben, die ZOD -Schemata als Parameter akzeptieren. Auf diese Weise können Sie eine benutzerdefinierte Validierungslogik, Schema -Transformationen und mehr erstellen und gleichzeitig die Sicherheit und Inferenz bei der Art und Inferenz beibehalten.
Wenn Sie versuchen, eine Funktion zu schreiben, die ein ZOD -Schema als Eingabe akzeptiert, ist es verlockend, so etwas auszuprobieren:
function inferSchema < T > ( schema : z . ZodType < T > ) {
return schema ;
}
Dieser Ansatz ist falsch und begrenzt die Fähigkeit von TypeScript, das Argument ordnungsgemäß zu schließen. 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