https://zod.dev
Проверка схемы с схемой типовой
Эти документы были переведены на китайский.
npm
(узел/булочка)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()
для решения общих проблем с z.coerce
. ZOD-это библиотека объявления и проверки схемы и проверки TypeScript. Я использую термин «схема», чтобы в целом ссылаться на любой тип данных, от простой string
до сложного вложенного объекта.
ZOD разработан как можно более удобным для разработчиков. Цель состоит в том, чтобы устранить дублирующие заявления типа. С помощью ZOD вы объявляете валидатор один раз , и ZOD автоматически выводит тип статического типового типа. Легко составить более простые типы в сложные структуры данных.
Некоторые другие замечательные аспекты:
.optional()
) возвращают новый экземплярСпонсорство на любом уровне ценится и поощряется. Если вы создали платный продукт с помощью ZOD, рассмотрите один из корпоративных уровней.
Самая полная платформа управления пользователями
CLERK.com
|
|
|
|
|
Пропелат | Cerbos | Скаляр | Trigger.dev |
Transloadit | Индивидуальный | Whop | Cryptojobslist |
Простой. | Innest | Storyblok | Мультинг |
Брэндон Байер | Jiří brabec | Алекс Йоханссон | Объединенные системы |
Адаптируется | Авана кошелек | Джейсон Ленгсторф | Global Illumination, Inc. |
Мастерство | Райан Палмер | Майкл Суини | NextBase |
Удаление | Коннор Синнотт | Мохаммад-али А'раби | Supatool |
Растет количество инструментов, которые строятся на вершине или поддерживают Zod изначально! Если вы создали инструмент или библиотеку на вершине ZOD, расскажите мне об этом в Twitter или начните обсуждение. Я добавлю его ниже и напишу в Твиттере.
tRPC
: Построить сквозные API-интерфейсы Typesafe без GraphQL.@anatine/zod-nestjs
: вспомогательные методы использования ZOD в проекте NESTJS.zod-endpoints
: Контрактный первый строго набрал конечные точки с ZOD. OpenAPI совместим.zhttp
: openAPI, совместимая, строго напечатанная библиотека HTTP с ZOD вводом и проверкой ответов.domain-functions
: отделите свою бизнес-логику из вашей структуры, используя композиционные функции. С первоклассным выводом типа от конечного до конца, питаемым от схемы ZOD.@zodios/core
: клиент API Typescript со временем выполнения и проверкой времени компиляции, поддерживаемой Axios и Zod.express-zod-api
: построить API на основе экспресса с валидацией схемы ввода/вывода и пользовательскими средним уровнем.tapiduck
: сквозные API-файлы json с Zod и Express; Немного похоже на TRPC, но проще.koa-zod-router
: создавать маршруты Typesafe в KOA с проверкой ввода/вывода с использованием ZOD.zod-sockets
: ZOD-мощный сокет.io MicroFramework с проверкой ввода/вывода и встроенными асинкейпи react-hook-form
: первой стороны ZOD Resolver для формы React Hook.zod-validation-error
: генерировать удобные сообщения об ошибках от ZodError
S.zod-formik-adapter
: адаптер Formik, поддержанный сообществом для ZOD.react-zorm
: автономная <form>
генерация и валидация для React с использованием ZOD.zodix
: ZOD Utilities for FormData и UrlSearchParams в ремикс -загрузчиках и действиях.conform
: библиотека проверки формы Typesafe для прогрессивного улучшения HTML -форм. Работает с ремиксом и Next.js.remix-params-helper
: упростите интеграцию ZOD со стандартными URLSearchParams и FormData для приложений Remix.formik-validator-zod
: Formik-совместимая библиотека валидаторов, которая упрощает использование ZOD с Formik.zod-i18n-map
: полезно для перевода сообщений об ошибках ZOD.@modular-forms/solid
: библиотека модульной формы для SolidJS, которая поддерживает ZOD для проверки.houseform
: библиотека форм реагирования, которая использует ZOD для проверки.sveltekit-superforms
: библиотека форм с наддувом для Sveltekit с проверкой ZOD.mobx-zod-form
: Data-first form builder based on MobX & Zod.@vee-validate/zod
: Form library for Vue.js with Zod schema validation.zod-form-renderer
: Auto-infer form fields from zod schema and render them with react-hook-form with E2E type safety. zod-to-ts
: генерируйте определения типографии из схемы ZOD.zod-to-json-schema
: преобразуйте свои схемы ZOD в схемы JSON.@anatine/zod-openapi
: преобразует схему ZOD в OpenApi v3.x SchemaObject
.zod-fast-check
: генерируйте fast-check
производители из схем ZOD.zod-dto
: Generate Nest.js DTOs from a Zod schema.fastify-type-provider-zod
: Create Fastify type providers from Zod schemas.zod-to-openapi
: генерируйте полные документы OpenAPI (Swagger) от ZOD, включая схемы, конечные точки и параметры.nestjs-graphql-zod
: генерирует классы модели nestjs graphql из схем Zod. Предоставляет декораторы метода GraphQL, работающие с схемами ZOD.zod-openapi
: Создайте полную документацию Openapi v3.x из схемы ZOD.fastify-zod-openapi
: Фастификация поставщика типов, проверка, сериализация и поддержка Fastify/Swagger для схем ZOD.typeschema
: универсальный адаптер для проверки схемы.zodex
: (de) сериализация для схемы ZOD ts-to-zod
: преобразовать определения типографии в схемы ZOD.@runtyping/zod
: генерируйте ZOD от статических типов и схемы JSON.json-schema-to-zod
: преобразовать свои схемы JSON в схемы ZOD. Живая демонстрация.json-to-zod
: преобразовать объекты JSON в схемы ZOD. Живая демонстрация.graphql-codegen-typescript-validation-schema
: плагин генератора кода GraphQL для генерации схемы проверки формы из вашей схемы GraphQL.zod-prisma
: генерируйте схемы ZOD от вашей схемы Prisma.Supervillain
: генерируйте схемы ZOD из ваших структур Go.prisma-zod-generator
: Emit zod схемы из вашей схемы Prisma.drizzle-zod
: излучает схемы ZOD из вашей схемы дождей.prisma-trpc-generator
: излучает полностью реализованные маршрутизаторы TRPC и их схемы проверки с использованием ZOD.zod-prisma-types
создают типы ZOD из ваших моделей Prisma.quicktype
: преобразовать объекты JSON и схемы JSON в схемы ZOD.@sanity-typed/zod
: генерировать схемы зод от Sanity Schemas.java-to-zod
: обрать pojos в схемы ZodOrval
: генерируйте схемы ZOD из схемы OpenAPIKubb
: генерируйте схемы SDK и ZOD из ваших схем OpenAPI @anatine/zod-mock
: генерируйте фиктивные данные из схемы ZOD. Приведено в действие Faker.js.zod-mocking
: генерируйте фиктивные данные из ваших схем ZOD.zod-fixture
: используйте свои схемы ZOD для автоматизации генерации нерелевантных тестовых приборов детерминированными способами.zocker
: генерируйте правдоподобные мак-даты из ваших схем.zodock
генерирует фиктивные данные на основе схемы ZOD.zod-schema-faker
Generates mock data from Zod schemas. Powered by @faker-js/faker и randexp.js freerstore
: Firestore Optimizer.slonik
: Node.js Postgres Client с сильной интеграцией ZOD.schemql
: Улучшает ваш рабочий процесс SQL, объединив необработанный SQL с целевой безопасностью типа и проверкой схемы.soly
: Создайте приложения CLI с ZOD.pastel
: создайте приложения CLI с React, Zod и чернилами.zod-xlsx
: валидатор ресурсов на основе XLSX с использованием схемы ZOD.znv
: тип-защищенная среда, анализ среды и проверка для node.js с схемами ZOD.zod-config
: Загрузите конфигурации по нескольким источникам с гибкими адаптерами, обеспечивая безопасность типа с помощью ZOD.unplugin-environment
: плагин для безопасной загрузки переменных среды с помощью проверки схемы, простым с виртуальным модулем, типовой защитник с Intellisense и лучший DX? Питается Zod. zod_utilz
: фреймворк -агностические утилиты для Zod.zod-playground
: инструмент для обучения и тестирования функциональности проверки схемы ZOD. Связь.zod-sandbox
: контролируемая среда для тестирования схем ZOD. Живая демонстрация.zod-dev
: условно отключает анализ времени выполнения ZOD в производстве.zod-accelerator
: ускоряет пропускную способность Зода до ~ 100x. TypeScript 4.5+!
Вы должны включить strict
режим в своем tsconfig.json
. Это лучшая практика для всех проектов TypeScript.
// tsconfig.json
{
// ...
"compilerOptions" : {
// ...
"strict" : true
}
}
npm
(узел/булочка) npm install zod # npm
yarn add zod # yarn
bun add zod # bun
pnpm add zod # pnpm
Zod также публикует канарейскую версию на каждом коммите. Чтобы установить канарейку:
npm install zod@canary # npm
yarn add zod@canary # yarn
bun add zod@canary # bun
pnpm add zod@canary # pnpm
deno.land/x
(deno)В отличие от узла, Deno полагается на прямой импорт URL, а не на диспетчер пакетов, как NPM. ZOD доступен на Deno.land/x. Последняя версия может быть импортирована так:
import { z } from "https://deno.land/x/zod/mod.ts" ;
Вы также можете указать определенную версию:
import { z } from "https://deno.land/x/[email protected]/mod.ts" ;
Остальная часть этого Readme предполагает, что вы используете NPM и импортируете непосредственно из пакета
"zod"
.
Создание простой строковой схемы
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 }
Создание объектной схемы
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 ( ) ;
Зод теперь обеспечивает более удобный способ принуждения примитивных значений.
const schema = z . coerce . string ( ) ;
schema . parse ( "tuna" ) ; // => "tuna"
schema . parse ( 12 ) ; // => "12"
На этапе анализа вход проходит через функцию String()
, которая представляет собой JavaScript, встроенный для данных принуждения в строки.
schema . parse ( 12 ) ; // => "12"
schema . parse ( true ) ; // => "true"
schema . parse ( undefined ) ; // => "undefined"
schema . parse ( null ) ; // => "null"
Возвращенная схема - это обычный экземпляр ZodString
, поэтому вы можете использовать все методы строк.
z . coerce . string ( ) . email ( ) . min ( 5 ) ;
Как работает принуждение
Все примитивные типы поддерживают принуждение. ZOD принуждает все входы с использованием встроенных конструкторов: String(input)
, Number(input)
, new Date(input)
и т. Д.
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)
Примечание - логическое принуждение с z.coerce.boolean()
может не работать так, как вы ожидаете. Любая правдивая ценность принуждается к true
, и любая фальшивая ценность принуждается к 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
Для большего контроля над логикой принуждения рассмотрите возможность использования z.preprocess
или z.pipe()
.
Литеральные схемы представляют собой буквальный тип, например "hello world"
или 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"
В настоящее время в ZOD нет поддержки литералов дат. Если у вас есть вариант использования для этой функции, пожалуйста, подайте проблему.
ZOD включает в себя несколько видов, специфичных для строк.
// 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 ( ) ;
Check out validator.js for a bunch of other useful string validation functions that can be used in conjunction with Refinements.
Вы можете настроить некоторые общие сообщения об ошибках при создании строковой схемы.
const name = z . string ( {
required_error : "Name is required" ,
invalid_type_error : "Name must be a string" ,
} ) ;
При использовании методов проверки вы можете передать дополнительный аргумент, чтобы предоставить пользовательское сообщение об ошибке.
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" } ) ;
Как вы, возможно, заметили, ZOD String включает в себя несколько валидаций, связанных с датой/времени. Эти проверки основаны на регулярном выражении, поэтому они не так строги, как библиотека полной даты/времени. Тем не менее, они очень удобны для проверки пользовательского ввода.
Метод z.string().datetime()
обеспечивает соблюдение ISO 8601; По умолчанию не смещений часового пояса и произвольная десятичная точность за второй второй.
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
на 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)
Вы можете дополнительно ограничить допустимую precision
. По умолчанию поддерживается произвольная точность подсекунды (но необязательно).
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
Добавлено в ZOD 3.23
Метод z.string().date()
проверяет строки в формате 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
Добавлено в ZOD 3.23
Метод z.string().time()
проверяет строки в формате HH:MM:SS[.s+]
. Второе может включать произвольную десятичную точность. Это не допускает каких -либо смешений часового пояса любого рода.
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)
Вы можете установить опцию precision
, чтобы ограничить допустимую десятичную точность.
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
Метод z.string().ip()
по умолчанию подтверждает IPv4 и 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
Вы можете дополнительно установить 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
Вы можете настроить определенные сообщения об ошибках при создании численной схемы.
const age = z . number ( {
required_error : "Age is required" ,
invalid_type_error : "Age must be a number" ,
} ) ;
ZOD включает в себя несколько подтверждений, специфичных для числа.
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
При желании вы можете передать второй аргумент, чтобы предоставить пользовательское сообщение об ошибке.
z . number ( ) . lte ( 5 , { message : "this?is?too?big" } ) ;
ZOD включает в себя несколько валидаций, специфичных для 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.
Вы можете настроить определенные сообщения об ошибках при создании схемы NAN.
const isNaN = z . nan ( {
required_error : "isNaN is required" ,
invalid_type_error : "isNaN must be 'not a number'" ,
} ) ;
Вы можете настроить определенные сообщения об ошибках при создании логической схемы.
const isActive = z . boolean ( {
required_error : "isActive is required" ,
invalid_type_error : "isActive must be a boolean" ,
} ) ;
Используйте z.date () для проверки экземпляров Date
.
z . date ( ) . safeParse ( new Date ( ) ) ; // success: true
z . date ( ) . safeParse ( "2022-01-12T00:00:00.000Z" ) ; // success: false
Вы можете настроить определенные сообщения об ошибках при создании схемы даты.
const myDateSchema = z . date ( {
required_error : "Please select a date and time" ,
invalid_type_error : "That's not a date!" ,
} ) ;
ZOD предоставляет несколько валидаций для конкретной даты.
z . date ( ) . min ( new Date ( "1900-01-01" ) , { message : "Too old" } ) ;
z . date ( ) . max ( new Date ( ) , { message : "Too young!" } ) ;
Принуждение на сегодняшний день
Со времени ZOD 3.20 используйте z.coerce.date()
чтобы пройти вход через 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
Для старых версий ZOD используйте z.preprocess
, как описано в этой теме.
const FishEnum = z . enum ( [ "Salmon" , "Tuna" , "Trout" ] ) ;
type FishEnum = z . infer < typeof FishEnum > ;
// 'Salmon' | 'Tuna' | 'Trout'
z.enum
-это ZOD-нюдентный способ объявить схему с фиксированным набором допустимых строковых значений. Передайте массив значений непосредственно в z.enum()
. В качестве альтернативы используйте as const
, чтобы определить значения перечисления как кортеж из строк. Смотрите документы Const Assertion для получения подробной информации.
const VALUES = [ "Salmon" , "Tuna" , "Trout" ] as const ;
const FishEnum = z . enum ( VALUES ) ;
Это не разрешено, поскольку ZOD не в состоянии вывести точные значения каждого элемента.
const fish = [ "Salmon" , "Tuna" , "Trout" ] ;
const FishEnum = z . enum ( fish ) ;
.enum
Чтобы получить автозаполнение с Zod Enum, используйте свойство .enum
вашей схемы:
FishEnum . enum . Salmon ; // => autocompletes
FishEnum . enum ;
/*
=> {
Salmon: "Salmon",
Tuna: "Tuna",
Trout: "Trout",
}
*/
Вы также можете получить список вариантов как кортеж с свойством .options
:
FishEnum . options ; // ["Salmon", "Tuna", "Trout"];
.exclude/.extract()
Вы можете создать подмножества ZOD Enum с помощью методов .exclude
и .extract
.
const FishEnum = z . enum ( [ "Salmon" , "Tuna" , "Trout" ] ) ;
const SalmonAndTrout = FishEnum . extract ( [ "Salmon" , "Trout" ] ) ;
const TunaOnly = FishEnum . exclude ( [ "Salmon" , "Trout" ] ) ;
ZOD Enums - это рекомендуемый подход к определению и проверке перечислений. Но если вам нужно подтвердить против перечисления из сторонней библиотеки (или вы не хотите переписать свои существующие перечисления), вы можете использовать z.nativeEnum()
.
Числовые перечисления
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
Строка перечисления
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
Константные перечисления
The .nativeEnum()
function works for as const
objects as well.as const
требуется 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
You can access the underlying object with the .enum
property:
FruitEnum . enum . Apple ; // "apple"
Вы можете сделать любую схему необязательной с z.optional()
. Это завершает схему в ZodOptional
и возвращает результат.
const schema = z . optional ( z . string ( ) ) ;
schema . parse ( undefined ) ; // => returns undefined
type A = z . infer < typeof schema > ; // string | undefined
Для удобства вы также можете вызвать метод .optional()
на существующей схеме.
const user = z . object ( {
username : z . string ( ) . optional ( ) ,
} ) ;
type C = z . infer < typeof user > ; // { username?: string | undefined };
Вы можете извлечь обернутую схему из ZodOptional
Exmance с .unwrap()
.
const stringSchema = z . string ( ) ;
const optionalString = stringSchema . optional ( ) ;
optionalString . unwrap ( ) === stringSchema ; // true
Точно так же вы можете создавать нулевые типы с z.nullable()
.
const nullableString = z . nullable ( z . string ( ) ) ;
nullableString . parse ( "asdf" ) ; // => "asdf"
nullableString . parse ( null ) ; // => null
Или используйте метод .nullable()
.
const E = z . string ( ) . nullable ( ) ; // equivalent to nullableString
type E = z . infer < typeof E > ; // string | null
Извлеките внутреннюю схему с помощью .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
Используйте .shape
для доступа к схемам для конкретного ключа.
Dog . shape . name ; // => string schema
Dog . shape . age ; // => number schema
.keyof
Используйте .keyof
для создания схемы ZodEnum
из ключей схемы объекта.
const keySchema = Dog . keyof ( ) ;
keySchema ; // ZodEnum<["name", "age"]>
.extend
Вы можете добавить дополнительные поля в схему объекта с помощью метода .extend
.
const DogWithBreed = Dog . extend ( {
breed : z . string ( ) ,
} ) ;
Вы можете использовать .extend
Будьте осторожны с этой силой!
.merge
Эквивалент 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 }
Если две схемы разделяют ключи, свойства B переопределяют свойство A. возвращенная схема также наследует политику «неизвестных» (полоса/строгая/проходная информация) и схема улова B.
.pick/.omit
Вдохновленные встроенными типовыми типами Pick
и Omit
утилит, все схемы объектов ZOD имеют методы .pick
и .omit
, которые возвращают модифицированную версию. Рассмотрим эту схему рецепта:
const Recipe = z . object ( {
id : z . string ( ) ,
name : z . string ( ) ,
ingredients : z . array ( z . string ( ) ) ,
} ) ;
Чтобы сохранить только определенные ключи, используйте .pick
.
const JustTheName = Recipe . pick ( { name : true } ) ;
type JustTheName = z . infer < typeof JustTheName > ;
// => { name: string }
Чтобы удалить определенные ключи, используйте .omit
const NoIDRecipe = Recipe . omit ( { id : true } ) ;
type NoIDRecipe = z . infer < typeof NoIDRecipe > ;
// => { name: string, ingredients: string[] }
.partial
Вдохновленный встроенным типовым типовым типом утилиты, .partial
метод делает все свойства необязательными.
Начиная с этого объекта:
const user = z . object ( {
email : z . string ( ) ,
username : z . string ( ) ,
} ) ;
// { email: string; username: string }
Мы можем создать частичную версию:
const partialUser = user . partial ( ) ;
// { email?: string | undefined; username?: string | undefined }
Вы также можете указать, какие свойства сделать необязательными:
const optionalEmail = user . partial ( {
email : true ,
} ) ;
/*
{
email?: string | undefined;
username: string
}
*/
.deepPartial
.partial
метод мелкий - он применяет только один уровень глубиной. Есть также «глубокая» версия:
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}[]
}
*/
Важное ограничение: глубокие частичные работают только как и ожидалось в иерархиях объектов, массивов и кортежей.
.required
В отличие от .partial
метод, .required
метод делает все свойства необходимыми.
Начиная с этого объекта:
const user = z
. object ( {
email : z . string ( ) ,
username : z . string ( ) ,
} )
. partial ( ) ;
// { email?: string | undefined; username?: string | undefined }
Мы можем создать требуемую версию:
const requiredUser = user . required ( ) ;
// { email: string; username: string }
Вы также можете указать, какие свойства сделать необходимыми:
const requiredEmail = user . required ( {
email : true ,
} ) ;
/*
{
email: string;
username?: string | undefined;
}
*/
.passthrough
По умолчанию схемы объекта ZOD разделяют непризнанные ключи во время анализа.
const person = z . object ( {
name : z . string ( ) ,
} ) ;
person . parse ( {
name : "bob dylan" ,
extraKey : 61 ,
} ) ;
// => { name: "bob dylan" }
// extraKey has been stripped
Вместо этого, если вы хотите пройти через неизвестные ключи, используйте .passthrough()
.
person . passthrough ( ) . parse ( {
name : "bob dylan" ,
extraKey : 61 ,
} ) ;
// => { name: "bob dylan", extraKey: 61 }
.strict
По умолчанию схемы объекта ZOD разделяют непризнанные ключи во время анализа. Вы можете запретить неизвестные ключи с .strict()
. Если на входе есть какие -либо неизвестные ключи, ZOD вынесет ошибку.
const person = z
. object ( {
name : z . string ( ) ,
} )
. strict ( ) ;
person . parse ( {
name : "bob dylan" ,
extraKey : 61 ,
} ) ;
// => throws ZodError
.strip
Вы можете использовать метод .strip
для сброса схемы объекта в поведение по умолчанию (снятие нераспознанных ключей).
.catchall
Вы можете передать схему «ловкость» в схему объекта. Все неизвестные ключи будут подтверждены против него.
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
Using .catchall()
obviates .passthrough()
, .strip()
, or .strict()
. Все ключи теперь считаются «известными».
const stringArray = z . array ( z . string ( ) ) ;
// equivalent
const stringArray = z . string ( ) . array ( ) ;
Be careful with the .array()
method. Возвращает новый экземпляр ZodArray
. Это означает, что порядок , в котором вы называете методы, имеет значение. Например:
z . string ( ) . optional ( ) . array ( ) ; // (string | undefined)[]
z . string ( ) . array ( ) . optional ( ) ; // string[] | undefined
.element
Используйте .element
для доступа к схеме для элемента массива.
stringArray . element ; // => string schema
.nonempty
Если вы хотите убедиться, что массив содержит хотя бы один элемент, используйте .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
Вы можете указать пользовательское сообщение об ошибке:
// 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
В отличие от .nonempty()
эти методы не изменяют предполагаемый тип.
В отличие от массивов, кортежи имеют фиксированное количество элементов, и каждый элемент может иметь другой тип.
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 }]
Аргумент переменного («REST») может быть добавлен с помощью метода .rest
.
const variadicTuple = z . tuple ( [ z . string ( ) ] ) . rest ( z . number ( ) ) ;
const result = variadicTuple . parse ( [ "hello" , 1 , 2 , 3 ] ) ;
// => [string, ...number[]];
ZOD включает в себя встроенный метод z.union
для сочинения "или" типов.
const stringOrNumber = z . union ( [ z . string ( ) , z . number ( ) ] ) ;
stringOrNumber . parse ( "foo" ) ; // passes
stringOrNumber . parse ( 14 ) ; // passes
ZOD проверит ввод по каждому из «параметров» в порядке и вернет первое значение, которое успешно проверяет.
Для удобства вы также можете использовать .or
.
const stringOrNumber = z . string ( ) . or ( z . number ( ) ) ;
Необязательная проверка строки:
Чтобы проверить необязательный ввод формы, вы можете объединить желаемую проверку строки с пустой буквой строки.
Этот пример подтверждает вход, который является необязательным, но должен содержать допустимый URL:
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
Дискриминационный союз - это союз схем объектов, которые все разделяют конкретный ключ.
type MyUnion =
| { status : "success" ; data : string }
| { status : "failed" ; error : Error } ;
Такие профсоюзы могут быть представлены с помощью метода z.discriminatedUnion
. Это обеспечивает более быструю оценку, потому что ZOD может проверить ключ дискриминатора ( status
в примере выше), чтобы определить, какая схема следует использовать для анализа ввода. Это делает анализ более эффективным и позволяет ZOD сообщать о более дружелюбных ошибках.
С помощью базового метода объединения вход проверяется на каждом из предоставленных «параметров», и в случае недействительности проблемы для всех «опций» показаны при ошибке ZOD. С другой стороны, дискриминационный союз позволяет выбрать только один из «вариантов», тестировать против него и показывать только проблемы, связанные с этой «опцией».
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" } ) ;
Вы можете извлечь ссылку на массив схем с свойством .options
.
myUnion . options ; // [ZodObject<...>, ZodObject<...>]
Чтобы объединить два или более дискриминационных союзов, используйте .options
с деструктуризацией.
const A = z . discriminatedUnion ( "status" , [
/* options */
] ) ;
const B = z . discriminatedUnion ( "status" , [
/* options */
] ) ;
const AB = z . discriminatedUnion ( "status" , [ ... A . options , ... B . options ] ) ;
Схемы записей используются для проверки типов, таких как Record<string, number>
. Это особенно полезно для хранения или кэширования элементов по 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 }>
Схема и предполагаемый тип можно использовать так:
const userStore : UserStore = { } ;
userStore [ "77d2586b-9e8e-4ecf-8b21-ea7e0530eadd" ] = {
name : "Carlotta" ,
} ; // passes
userStore [ "77d2586b-9e8e-4ecf-8b21-ea7e0530eadd" ] = {
whatever : "Ice cream sundae" ,
} ; // TypeError
Примечание на числовых ключах
В то время как z.record(keyType, valueType)
способен принимать численные типы ключей, а встроенный тип записи TypeScript-это Record<KeyType, ValueType>
, трудно представить Record<number, any>
в ZOD.
Оказывается, поведение TypeScript, окружающее [k: number]
, немного неинтуитивно:
const testMap : { [ k : number ] : string } = {
1 : "one" ,
} ;
for ( const key in testMap ) {
console . log ( ` ${ key } : ${ typeof key } ` ) ;
}
// prints: `1: string`
Как вы можете видеть, JavaScript автоматически бросает все ключи объектов на струны под капотом. Поскольку ZOD пытается преодолеть разрыв между статическими типами и типами выполнения, не имеет смысла обеспечить способ создания схемы записи с помощью числовых ключей, поскольку нет такого понятия, как числовой ключ в 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>
Установленные схемы могут быть дополнительно ограничены следующими методами утилиты.
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
Перекрестки полезны для создания «логических и» типов. Это полезно для пересечения двух типов объектов.
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 ) ;
Хотя во многих случаях рекомендуется использовать A.merge(B)
для объединения двух объектов. Метод .merge
возвращает новый экземпляр ZodObject
, тогда как A.and(B)
возвращает менее полезный экземпляр ZodIntersection
, в котором отсутствуют общие методы объектов, такие как pick
и 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
Вы можете определить рекурсивную схему в ZOD, но из -за ограничения TypeScript их тип не может быть статически. Вместо этого вам нужно определить определение типа вручную и предоставить его ZOD как «подсказка типа».
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
Спасибо Crasite за этот пример.
При использовании z.ZodType
с z.ZodEffects
( .refine
, .transform
, preprocess
и т. Д.) Вам необходимо будет определить типы ввода и вывода схемы. 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 ( ) ) ,
} ) ;
Спасибо Marcus13371337 и Joelbeeldi за этот пример.
Если вы хотите проверить какое -либо значение JSON, вы можете использовать фрагмент ниже.
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 ) ;
Спасибо Ggoodman за то, что он предложил это.
Несмотря на поддержку рекурсивных схем, передача циклических данных в ZOD в некоторых случаях вызовет бесконечную петлю.
To detect cyclical objects before they cause problems, consider this approach.
const numberPromise = z . promise ( z . number ( ) ) ;
«Сборник» работает немного по -другому с схемами обещаний. Валидация происходит в двух частях:
.then
и .catch
.)..then
для прикрепления дополнительного шага проверки к существующему обещанию. Вам придется использовать .catch
на возвращенном обещании обрабатывать сбои проверки. 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
} ;
Вы можете использовать z.instanceof
, чтобы проверить, что вход является экземпляром класса. Это полезно для проверки входных данных против классов, которые экспортируются из сторонних библиотек.
class Test {
name : string ;
}
const TestSchema = z . instanceof ( Test ) ;
const blob : any = "whatever" ;
TestSchema . parse ( new Test ( ) ) ; // passes
TestSchema . parse ( blob ) ; // throws
Зод также позволяет определить «схемы функций». Это позволяет легко проверять входы и выходы функции, не смешивая код проверки и «бизнес -логику».
Вы можете создать функциональную схему с помощью z.function(args, returnType)
.
const myFunction = z . function ( ) ;
type myFunction = z . infer < typeof myFunction > ;
// => ()=>unknown
Определите входы и выходы.
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
Функциональные схемы имеют метод .implement()
, который принимает функцию и возвращает новую функцию, которая автоматически проверяет ее входы и выходы.
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
Если вы заботитесь только об проверке входов, просто не вызовите метод. .returns()
. Тип вывода будет выведен из реализации.
Вы можете использовать опцию Special
z.void()
, если ваша функция ничего не возвращает. Это позволит ZOD должным образом вывести тип функций пустоты. (Функции void rewurning фактически возвращают неопределенные.)
const myFunction = z
. function ( )
. args ( z . string ( ) )
. implement ( ( arg ) => {
return [ arg . length ] ;
} ) ;
myFunction ; // (arg: string)=>number[]
Извлеките входные и выходные схемы из функциональной схемы.
myFunction . parameters ( ) ;
// => ZodTuple<[ZodString, ZodNumber]>
myFunction . returnType ( ) ;
// => ZodBoolean
Зод теперь поддерживает примитивное принуждение без необходимости
.preprocess()
. Смотрите документы о принуждении для получения дополнительной информации.
Как правило, ZOD работает под парадигмой «Parse Transform». ZOD сначала проверяет вход, а затем передает его через цепочку функций преобразования. (Для получения дополнительной информации о преобразовании прочитайте. Transform Docs.)
Но иногда вы хотите применить некоторое преобразование к вводу, прежде чем пройдет анализ. Общий вариант использования: тип принуждения. ZOD позволяет это с z.preprocess()
.
const castToString = z . preprocess ( ( val ) => String ( val ) , z . string ( ) ) ;
Это возвращает экземпляр ZodEffects
. ZodEffects
- это класс обертки, который содержит всю логику, относящуюся к предварительной обработке, усовершенствованиям и преобразованиям.
Вы можете создать схему ZOD для любого типа TypeScript с помощью z.custom()
. Это полезно для создания схем для типов, которые не поддерживаются ZOD из коробки, такие как литералы с шаблонами.
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;
Если вы не предоставите функцию проверки, ZOD разрешит любое значение. Это может быть опасно!
z . custom < { arg : string } > ( ) ; // performs no validation
You can customize the error message and other options by passing a second argument. Этот параметр работает так же, как параметр Params .refine
.
z . custom < ... > ( ( val ) => ... , "custom error message" ) ;
Все схемы ZOD содержат определенные методы.
.parse
.parse(data: unknown): T
Учитывая любую схему ZOD, вы можете вызвать его метод .parse
, чтобы проверить data
, действителен. Если это так, значение возвращается с полной информацией! В противном случае ошибку брошен.
Важно: значение, возвращаемое
.parse
- это глубокий клон переменной, в которой вы передали.
const stringSchema = z . string ( ) ;
stringSchema . parse ( "fish" ) ; // => returns "fish"
stringSchema . parse ( 12 ) ; // throws error
.parseAsync
.parseAsync(data:unknown): Promise<T>
Если вы используете асинхронные усовершенствования или преобразования (подробнее о них позже), вам нужно использовать .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; }
Если вы не хотите, чтобы ZOD бросал ошибки при сбое проверки, используйте .safeParse
. Этот метод возвращает объект, содержащий либо успешно проанализированные данные, или экземпляр Zoderror, содержащий подробную информацию о задачах проверки.
stringSchema . safeParse ( 12 ) ;
// => { success: false; error: ZodError }
stringSchema . safeParse ( "billie" ) ;
// => { success: true; data: 'billie' }
Результатом является дискриминационный союз , поэтому вы можете очень удобно обрабатывать ошибки:
const result = stringSchema . safeParse ( "billie" ) ;
if ( ! result . success ) {
// handle error then return
result . error ;
} else {
// do something
result . data ;
}
.safeParseAsync
Alias:
.spa
Асинхронная версия safeParse
.
await stringSchema . safeParseAsync ( "billie" ) ;
Для удобства, это было псевдонировано .spa
:
await stringSchema . spa ( "billie" ) ;
.refine
.refine(validator: (data:T)=>any, params?: RefineParams)
ZOD позволяет предоставлять пользовательскую логику проверки через усовершенствования . (Для расширенных функций, таких как создание нескольких проблем и настройка кодов ошибок, см .superRefine
.)
ZOD был разработан для зеркального TypeScript как можно ближе. Но есть много так называемых «типов уточнения», которые вы можете проверить, которые не могут быть представлены в системе типов типов. Например: проверка того, что число является целым числом или что строка является действительным адресом электронной почты.
Например, вы можете определить пользовательскую проверку проверки на любую схему ZOD с .refine
:
const myString = z . string ( ) . refine ( ( val ) => val . length <= 255 , {
message : "String can't be more than 255 characters" ,
} ) ;
️ Функции уточнения не должны бросать. Вместо этого они должны вернуть фальшивое значение для отказа сигнала.
Как видите, .refine
берет два аргумента.
T
- предполагаемый тип схемы) и возвращает any
. Любая правдивая ценность пройдет проверку. (До [email protected] функция проверки должна была вернуть логическое.) 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 ;
} ;
Для расширенных случаев второй аргумент также может быть функцией, которая возвращает 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" } ) ;
Поскольку вы предоставили параметр path
, полученная ошибка будет:
ZodError {
issues : [ {
"code" : "custom" ,
"path" : [ "confirm" ] ,
"message" : "Passwords don't match"
} ]
}
Усовершенствования также могут быть асинхронными:
const userId = z . string ( ) . refine ( async ( id ) => {
// verify that ID exists in database
return true ;
} ) ;
️ Если вы используете асинхронные усовершенствования, вы должны использовать метод.parseAsync
для анализа данных! В противном случае Зод вынесет ошибку.
Преобразования и усовершенствования могут быть чередованы:
z . string ( )
. transform ( ( val ) => val . length )
. refine ( ( val ) => val > 25 ) ;
.superRefine
Метод .refine
на самом деле является синтаксическим сахаром на более универсальном (и словесном) методе, называемом superRefine
. Вот пример:
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.` ,
} ) ;
}
} ) ;
Вы можете добавить столько проблем, сколько захотите. Если ctx.addIssue
не вызывается во время выполнения функции, проходит проверка.
Обычно усовершенствования всегда создают проблемы с кодом ошибки ZodIssueCode.custom
, но с superRefine
можно бросить проблемы любого ZodIssueCode
. Каждый код выпуска подробно описан в Руководстве по обработке ошибок: error_handling.md.
По умолчанию анализ будет продолжаться даже после того, как проверка уточнения не удастся. For instance, if you chain together multiple refinements, they will all be executed. Тем не менее, может быть желательно прервать рано, чтобы предотвратить выполнение более поздних уточнений. Чтобы достичь этого, передайте fatal
флаг в ctx.addIssue
и верните 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" ,
} ) ;
}
} ) ;
Если вы предоставите предикат типа .refine()
или .superRefine()
, полученный тип будет сужен до типа вашего предиката. Это полезно, если вы смешиваете усовершенствования и преобразования с несколькими цепями:
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`!" ) ;
️ You must usectx.addIssue()
instead of returning a boolean value to indicate whether the validation passes. Еслиctx.addIssue
не вызывается во время выполнения функции, проходит проверка.
.transform
Чтобы преобразовать данные после анализа, используйте метод transform
.
const stringToNumber = z . string ( ) . transform ( ( val ) => val . length ) ;
stringToNumber . parse ( "string" ) ; // => 6
Обратите внимание, что stringToNumber
выше является экземпляром подкласса ZodEffects
. Это не экземпляр ZodString
. Если вы хотите использовать встроенные методы ZodString
(например .email()
), вы должны применить эти методы перед какими-либо преобразованием.
const emailToDomain = z
. string ( )
. email ( )
. transform ( ( val ) => val . split ( "@" ) [ 1 ] ) ;
emailToDomain . parse ( "[email protected]" ) ; // => example.com
Метод .transform
может одновременно проверять и преобразовать значение. Это часто бывает проще и менее дублирует, чем transform
цепочек и refine
.
Как и в случае с .superRefine
, функция преобразования получает объект ctx
с помощью метода addIssue
, который можно использовать для вопросов проверки регистрации.
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 ;
} ) ;
Преобразования и усовершенствования могут быть чередованы. Они будут выполнены в порядке, который они объявлены.
const nameToGreeting = z
. string ( )
. transform ( ( val ) => val . toUpperCase ( ) )
. refine ( ( val ) => val . length > 15 )
. transform ( ( val ) => `Hello ${ val } ` )
. refine ( ( val ) => val . indexOf ( "!" ) === - 1 ) ;
Преобразования также могут быть асинхронными.
const IdToUser = z
. string ( )
. uuid ( )
. transform ( async ( id ) => {
return await getUserById ( id ) ;
} ) ;
️ Если ваша схема содержит асинхронные преобразования, вы должны использовать .parseasync () или .safeparseasync () для анализа данных. В противном случае Зод вынесет ошибку.
.default
Вы можете использовать преобразование для реализации концепции «значений по умолчанию» в ZOD.
const stringWithDefault = z . string ( ) . default ( "tuna" ) ;
stringWithDefault . parse ( undefined ) ; // => "tuna"
При желании вы можете передать функцию в .default
const numberWithRandomDefault = z . number ( ) . default ( Math . random ) ;
numberWithRandomDefault . parse ( undefined ) ; // => 0.4413456736055323
numberWithRandomDefault . parse ( undefined ) ; // => 0.1871840107401901
numberWithRandomDefault . parse ( undefined ) ; // => 0.7223408162401552
Концептуально, вот как ZOD обрабатывает значения по умолчанию:
undefined
, значение по умолчанию возвращается.describe
Используйте .describe()
, чтобы добавить свойство description
в полученную схему.
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…
Это может быть полезно для документирования поля, например, в схеме JSON с использованием библиотеки, такой как zod-to-json-schema
).
.catch
Используйте .catch()
, чтобы предоставить «значение вылова», чтобы быть возвращенным в случае ошибки анализа.
const numberWithCatch = z . number ( ) . catch ( 42 ) ;
numberWithCatch . parse ( 5 ) ; // => 5
numberWithCatch . parse ( "tuna" ) ; // => 42
При желании вы можете передать функцию в .catch
Объект ctx
, содержащий захваченную ошибку, будет передаваться в эту функцию.
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
Концептуально, именно так ZOD обрабатывает «значения поймать»:
.optional
Удобный метод, который возвращает дополнительную версию схемы.
const optionalString = z . string ( ) . optional ( ) ; // string | undefined
// equivalent to
z . optional ( z . string ( ) ) ;
.nullable
Удобный метод, который возвращает нулевую версию схемы.
const nullableString = z . string ( ) . nullable ( ) ; // string | null
// equivalent to
z . nullable ( z . string ( ) ) ;
.nullish
Удобный метод, который возвращает «нулевую» версию схемы. Nullish schemas will accept both undefined
and null
. Узнайте больше о концепции «Nullish» в заметках Typescript 3.7.
const nullishString = z . string ( ) . nullish ( ) ; // string | null | undefined
// equivalent to
z . string ( ) . nullable ( ) . optional ( ) ;
.array
A convenience method that returns an array schema for the given type:
const stringArray = z . string ( ) . array ( ) ; // string[]
// equivalent to
z . array ( z . string ( ) ) ;
.promise
Удобный метод для типов обещаний:
const stringPromise = z . string ( ) . promise ( ) ; // Promise<string>
// equivalent to
z . promise ( z . string ( ) ) ;
.or
Удобный метод для типов союзов.
const stringOrNumber = z . string ( ) . or ( z . number ( ) ) ; // string | number
// equivalent to
z . union ( [ z . string ( ) , z . number ( ) ] ) ;
.and
Удобный метод создания типов пересечения.
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>
Система типа TypeScript является структурной, что означает, что любые два типа, которые являются структурно эквивалентными, считаются одинаковыми.
type Cat = { name : string } ;
type Dog = { name : string } ;
const petCat = ( cat : Cat ) => { } ;
const fido : Dog = { name : "fido" } ;
petCat ( fido ) ; // works fine
In some cases, its can be desirable to simulate nominal typing inside TypeScript. For instance, you may wish to write a function that only accepts an input that has been validated by Zod. This can be achieved with branded types (AKA opaque types ).
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" } ) ;
Under the hood, this works by attaching a "brand" to the inferred type using an intersection type. Таким образом, простые/небранные структуры данных больше не назначаются для предполагаемого типа схемы.
const Cat = z . object ( { name : z . string ( ) } ) . brand < "Cat" > ( ) ;
type Cat = z . infer < typeof Cat > ;
// {name: string} & {[symbol]: "Cat"}
Обратите внимание, что фирменные типы не влияют на результат времени выполнения .parse
. Это статическая конструкция.
.readonly
.readonly() => ZodReadonly<this>
Этот метод возвращает экземпляр схемы ZodReadonly
, который анализирует вход, используя базовую схему, затем вызывает Object.freeze()
в результате. Предполагаемый тип также отмечен как 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
Предполагаемый тип использует встроенные типовые типы типовой чтения, когда это уместно.
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
Схемы могут быть привязаны к валидации «трубопроводы». Это полезно для легкости проверки результата после .transform()
:
z . string ( )
. transform ( ( val ) => val . length )
. pipe ( z . number ( ) . min ( 5 ) ) ;
Метод .pipe()
возвращает экземпляр ZodPipeline
.
.pipe()
для решения общих проблем с z.coerce
. Вы можете ограничить ввод на типы, которые хорошо работают с выбранным вами принуждением. Затем используйте .pipe()
чтобы применить принуждение.
без ограниченного ввода:
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
с ограниченным вводом:
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
Вы также можете использовать эту технику, чтобы избежать принуждения, которые бросают ошибки.
без ограниченного ввода:
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
с ограниченным вводом:
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
Вы можете извлечь тип типового типа любой схемы с 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
А как насчет трансформаций?
В действительности каждая схема ZOD внутренне отслеживает два типа: вход и выход. Для большинства схем (например, z.string()
) эти два одинаковы. Но как только вы добавите преобразования в микс, эти два значения могут расходиться. Например, z.string().transform(val => val.length)
имеет вход string
и вывод number
.
Вы можете отдельно извлечь входные и выходные типы, такие как SO:
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
С TypeScript Generics вы можете написать многократные функции, которые принимают схемы ZOD в качестве параметров. Это позволяет создавать пользовательскую логику проверки, преобразования схемы и многое другое, сохраняя при этом безопасность и вывод типа.
При попытке написать функцию, которая принимает схему ZOD в качестве ввода, заманчиво попробовать что -то подобное:
function inferSchema < T > ( schema : z . ZodType < T > ) {
return schema ;
}
This approach is incorrect, and limits TypeScript's ability to properly infer the argument. Независимо от того, что вы проходите, тип schema
станет экземпляром 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