Releases: colinhacks/zod
v3.21.1
Features
Support for ULID validation
z.string().ulid();
Commits:
- 4f89461 Prettier
- bd6527a Update deps
- 126c77b added
toLowerCase
andtoUpperCase
back in for v3.21.0 - 1749657 Update README.md
- dabe63d updated
z.custom
example again :D - 6b8f655 docs: improve cn readme (#2143)
- 9012dc7 add
.includes(value, options?)
@ZodString
. (#1887) - 67b981e Make safeParse().error a getter
- 346fde0 3.21.0-canary.20230304T235951
- b50d871 Add canary release CI
- b20cca2 Fix canary
- f7f5c50 Move action to .github/workflows
- f01fa0e Try to fix canary CI
- f5e8067 No git tag
- 5b304ae No dry run
- 20df80e Add tsc compilation test
- ead93d3 Document .pipe()
- d8e8653 Update headers
- 03c0ab1 Cache the evaluation of ParseInputLazyPath.path() for a moderate perf improvement (#2137)
- e7b3b7b Improve string docs
- 83478f5 Remove zod dep
- 2f1868d Specify paths for canary
- e599966 Add sponsors
- 950bd17 Tweak x.custom example
- 728e56a Close #2127
- 64883e4 feat: z.string().ulid() - add support for ulids (#2049)
- e0d709b 3.20.1
- 9c33194 Remove comments, clean up utils
- 942e2db Fix tests
v3.21.0
Features
z.string().emoji()
Thanks @joseph-lozano for #2045! To validate that all characters in a string are emoji:
z.string().emoji()
...if that's something you want to do for some reason.
z.string().cuid2()
Thanks @joulev for #1813! To validate CUIDv2:
z.string().cuid2()
z.string().ip()
Thanks @fvckDesa for #2066. To validate that a string is a valid IP address:
const v4IP = "122.122.122.122";
const v6IP = "6097:adfa:6f0b:220d:db08:5021:6191:7990";
// matches both IPv4 and IPv6 by default
const ipSchema = z.string().ip();
ipSchema.parse(v4IP) // pass
ipSchema.parse(v6IP) // pass
To specify a particular version
:
const ipv4Schema = z.string().ip({ version: "v4" });
const ipv6Schema = z.string().ip({ version: "v6" });
z.bigint().{gt|gte|lt|lte}()
Thanks @igalklebanov for #1711
! ZodBigInt
gets the same set of methods found on ZodNumber
:
z.bigint().gt(BigInt(5));
z.bigint().gte(BigInt(5));
z.bigint().lt(BigInt(5));
z.bigint().lte(BigInt(5));
z.bigint().positive();
z.bigint().negative();
z.bigint().nonnegative();
z.bigint().nonpositive();
z.bigint().multipleOf(BigInt(5));
z.enum(...).extract()
and z.enum(...).exclude()
Thanks @santosmarco-caribou for #1652! To add or remove elements from a ZodEnum
:
const FoodEnum = z.enum(["Pasta", "Pizza", "Tacos", "Burgers", "Salad"]);
const ItalianEnum = FoodEnum.extract(["Pasta", "Pizza"]); // ZodEnum<["Pasta", "Pizza"]>
const UnhealthyEnum = FoodEnum.exclude(["Salad"]); // ZodEnum<["Pasta", "Pizza", "Tacos", "Burgers"]>
This API is inspired by the Exclude
and Extract
TypeScript built-ins.
Pass a function to .catch()
Thanks @0xWryth for #2087! The .catch()
method now accepts a function that receives the caught error:
const numberWithErrorCatch = z.number().catch((ctx) => {
ctx.error; // ZodError
return 42;
});
Compiler performance
Zod 3.20.2 introduced an accidental type recursion that caused long compilation times for some users. These kinds of bugs are very hard to diagnose. Big shoutout to @gydroperit for some heroic efforts here: #2107 Zod 3.21 resolves these issues:
- #2142
- #1741
- https://stackoverflow.com/questions/74881472/slow-typescript-autocompletion-in-vs-code-for-zod
Commits:
- 3c54461 fix typo in readme
- c244fb6 feat: z.string().emoji() (#2045)
- 39cbb69 Fix emoji validation, fix lint
- d8f07bb Fix emoji
- 9b7dd81 Improve variable name clarity (#2048)
- 5cec187 Add documentation for the param parameter of z.custom
- 654f529 Merge pull request #2057 from trygveaa/add-documentation-for-z-custom-params
- 981af65 Merge pull request #2019 from vbud/patch-1
- a7c2969 Update error_handling
- 8f3d028 BRAND Record to Non Partial (#2097)
- 5ec98e1 Fix email issues in pull request #1982 (#2058)
- 7d40ba5 feat(#2059): z.string.ip() - add support for IP address (#2066)
- e559605 feat: add
.catch
error (#2087) - defdab9 Fix record tests
- 8de36eb FIX: emoji regex and tests (#2090)
- 16beeb5 lowercase method for ZodString (#2038)
- 75cb9e8 add checks @
ZodBigInt
. (#1711) - c4d4e49 Update ERROR_HANDLING.md (#2022)
- d6f0890 added link to deno land
- 4cf1960 Refactoring of ZodFormattedError type to improve tsc check time (#2107)
- 867a921 Bump http-cache-semantics from 4.1.0 to 4.1.1 (#1985)
- edc3a67 Deprecate deepPartial
- e59f639 Add custom tests
- a6b44ed Remove logging
- a1fc3fb commented out
toLowerCase
andtoUpperCase
- e71cc52 Update README_ZH.md (#2139)
- 3af38fb add
ZodNumber.safe()
&ZodNumber.isSafe
. (#1753) - 6ef82ee Add benchmark flags
- 5463593 Support brands in recursive types
- 8074523 Update readme
- b6794a4 Add index signature for passthrough
- 3c6cdd2 Make generic optional in objectOutputType
- bc43ad1 Fix rollup build
- 6a0545a 3.21.0
- 7c07339 Fix brand
- 0aa6021 Clean up tests
v3.20.6
v3.20.5
v3.20.4
v3.20.3
Features
- Add string cuid2() validation by @joulev in #1813
- Add
ZodNumber.isFinite
, makeZodNumber.isInt
true if.multipleOf(int)
. by @igalklebanov in #1714 - feat: Add
extract
/exclude
methods toZodEnum
by @santosmarco-caribou in #1652
Fixes and documentation
- add more test cases for
z.coerce
. by @igalklebanov in #1680 - Add Modular Forms to form integrations in README by @fabian-hiller in #1695
- docs: Instruct users to return z.NEVER in .superRefine() when providing a type predicate by @zetaraku in #1742
- Fix small typo in ERROR_HANDLING.md by @t-shiratori in #1720
- Improve accuracy of the
isAsync
type guard by @aaronccasanova in #1719 - fix: Fix
ZodCatch
by @santosmarco-caribou in #1733 - Fix datetime offset without comma by @ooga in #1749
- Discriminated union example fails to parse by @matthewfallshaw in #1713
- fix: [#1693] Tuple with empty items by @metuan in #1712
- fix: #1668 email regex safari compat by @AnatoleLucet in #1683
- docs: fix typo by @zetaraku in #1699
- fix installation links in table of contents by @DetachHead in #1700
- Updated
deno/lib/README.md
to matchzod/README.md
by @JacobWeisenburger in #1791 - fix(#1743): Fix passing params in root class by @santosmarco-caribou in #1756
- change the chaining order of nullish method by @p10ns11y in #1702
- Propagate custom error type to ZodFormattedError subfields by @carlgieringer in #1617
- fix deno literal test. by @igalklebanov in #1794
- Document
.describe()
by @rattrayalex in #1819 - update homepage link in package.json by @Gpx in #1830
- fix: compile error in sample code by @jtgi in #1822
- Readme: Move "Coercion for primitives" section by @tordans in #1842
- Readme: Add internal links "or" <-> "union" by @tordans in #1846
- Readme: Add example for string validation for an optional field to chapter "Unions" by @tordans in #1849
- Readme: Add intro to chapter Literals by @tordans in #1877
- fix: faker.js link in readme by @markacola in #1843
- Minor typo fix by @iamchandru6470 in #1945
- chore(documentation): Update CHANGELOG to redirect to Github Releases by @mitchwd in #1936
- fix: [#1839] remove caught errors from issues by @maxArturo in #1926
- fix: [#1784] dark mode in the documentation by @fvckDesa in #1932
- Allow also "[+-]hh" as datetime offset by @rafw87 in #1797
- Feature/add resolves method to zod promise by @bolencki13 in #1871
- test: add benchmark tests for date and symbol by @pnts-se in #1796
- export the email regex by @andresBobsled in #2007
- Add React form validation library to ecosystem by @crutchcorn in #1999
- fix: make sure only mask keys with truthy values are respected at runtime @
.pick
,.omit
,.partial
&.required
. by @igalklebanov in #1875 - fix: failing prettier checks on merge by @maxArturo in #1969
- deny unexpected keys @
ZodObject
's.omit(mask)
,.pick(mask)
,.required(mask)
&.partial(mask)
at compile time. by @igalklebanov in #1564 - docs: punctuation by @jly36963 in #1973
- fix[#1979]: Increment Email validation by @fvckDesa in #1982
- test: additional unit-tests for object by @pnts-se in #1729
New Contributors
- @fabian-hiller made their first contribution in #1695
- @zetaraku made their first contribution in #1742
- @t-shiratori made their first contribution in #1720
- @aaronccasanova made their first contribution in #1719
- @ooga made their first contribution in #1749
- @matthewfallshaw made their first contribution in #1713
- @metuan made their first contribution in #1712
- @AnatoleLucet made their first contribution in #1683
- @DetachHead made their first contribution in #1700
- @p10ns11y made their first contribution in #1702
- @carlgieringer made their first contribution in #1617
- @rattrayalex made their first contribution in #1819
- @Gpx made their first contribution in #1830
- @jtgi made their first contribution in #1822
- @tordans made their first contribution in #1842
- @markacola made their first contribution in #1843
- @iamchandru6470 made their first contribution in #1945
- @mitchwd made their first contribution in #1936
- @fvckDesa made their first contribution in #1932
- @rafw87 made their first contribution in #1797
- @bolencki13 made their first contribution in #1871
- @joulev made their first contribution in #1813
- @pnts-se made their first contribution in #1796
- @andresBobsled made their first contribution in #2007
- @crutchcorn made their first contribution in #1999
- @jly36963 made their first contribution in #1973
Full Changelog: v3.20.2...v3.20.3
v3.20.2
v3.20.1
v3.20
Breaking changes
There are no breaking API changes, however TypeScript versions 4.4
and earlier are no longer officially supported.
New features
The most feature-packed release since Zod 3.0!
.pipe()
A new schema method .pipe()
is now available on all schemas. which can be used to chain multiple schemas into a "validation pipeline". Typically this will be used in conjunction with .transform()
.
z.string()
.transform(val => val.length)
.pipe(z.number().min(5))
The .pipe()
method returns a ZodPipeline
instance.
z.coerce
Zod now provides a more convenient way to coerce primitive values.
const schema = z.coerce.string();
schema.parse("tuna"); // => "tuna"
schema.parse(12); // => "12"
schema.parse(true); // => "true"
During the parsing step, the input is passed through the String()
function, which is a JavaScript built-in for coercing data into strings. Note that the returned schema is a ZodString
instance so you can use all string methods.
z.coerce.string().email().min(5);
All primitive types support coercion.
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)
.catch()
A new schema method .catch()
is now available on all schemas. It can be used to provide a "catchall" value that will be returned in the event of a parsing error.
const schema = z.string().catch("fallback");
schema.parse("kate"); // => "kate"
schema.parse(4); // => "fallback"
The .catch()
method returns a ZodCatch
instance.
z.symbol()
A long-missing hole in Zod's type system is finally filled! Thanks @santosmarco-caribou.
const schema = z.symbol();
schema.parse(Symbol('asdf'));
Relatedly, you can also pass symbols into z.literal()
.
const TUNA = Symbol("tuna");
const schema = z.literal(TUNA);
schema.parse(TUNA); // Symbol(tuna)
schema.parse(Symbol("nottuna")); // Error
z.string().datetime()
A new method has been added to ZodString
to validate ISO datetime strings. Thanks @samchungy!
z.string().datetime();
This method defaults to only allowing UTC datetimes (the ones that end in "Z"
). No timezone offsets are allowed; arbitrary sub-second precision is supported.
const dt = z.string().datetime();
dt.parse("2020-01-01T00:00:00Z"); // 🟢
dt.parse("2020-01-01T00:00:00.123Z"); // 🟢
dt.parse("2020-01-01T00:00:00.123456Z"); // 🟢 (arbitrary precision)
dt.parse("2020-01-01T00:00:00+02:00"); // 🔴 (no offsets allowed)
Offsets can be supported with the offset
parameter.
const a = z.string().datetime({ offset: true });
a.parse("2020-01-01T00:00:00+02:00"); // 🟢 offset allowed
You can additionally constrain the allowable precision
. This specifies the number of digits that should follow the decimal point.
const b = z.string().datetime({ precision: 3 })
b.parse("2020-01-01T00:00:00.123Z"); // 🟢 precision of 3 decimal points
b.parse("2020-01-01T00:00:00Z"); // 🔴 invalid precision
z.number().finite()
Restrict a number schema to finite values. Thanks @igalklebanov.
const schema = z.number().finite();
schema.parse(5); 🟢
schema.parse(Infinity); 🔴
schema.parse(-Infinity); 🔴
What's Changed
- Add formik-validator-zod to README ecosystem links by @Glazy in #1662
- chore: add eslintcache by @Simon-He95 in #1629
- feat: #1602 narrow superRefine() type by @maxArturo in #1615
- Fix issue #1611 by @john-schmitz in #1620
- Fix typo in CHANGELOG.md by @eltociear in #1612
- docs: fix typo in Writing generic functions by @Rolanddoda in #1609
- docs: likely a minor typo by @JakeBruner in #1599
- Add znv to the Ecosystem by @vitorvanacor in #1591
- fix: #1638 and Redundant character escape '' in RegExp by @powerfulyang in #1648
- docs: update CONTRIBUTING.md links by @maxArturo in #1584
- Cleaned up some code snippets in docs by @V1RE in #1579
- docs: add
zod-i18n-map
to README ecosystem links by @aiji42 in #1666
New Contributors
- @Glazy made their first contribution in #1662
- @Simon-He95 made their first contribution in #1629
- @maxArturo made their first contribution in #1615
- @john-schmitz made their first contribution in #1620
- @eltociear made their first contribution in #1612
- @Rolanddoda made their first contribution in #1609
- @JakeBruner made their first contribution in #1599
- @powerfulyang made their first contribution in #1648
- @V1RE made their first contribution in #1579
- @aiji42 made their first contribution in #1666
Full Changelog: v3.20.0...v3.20
v3.20.0-beta
Breaking changes
There are no breaking API changes, however TypeScript versions 4.4
and earlier are no longer officially supported.
New features
The most feature-packed release since Zod 3.0!
.pipe()
A new schema method .pipe()
is now available on all schemas. which can be used to chain multiple schemas into a "validation pipeline". Typically this will be used in conjunction with .transform()
.
z.string()
.transform(val => val.length)
.pipe(z.number().min(5))
The .pipe()
method returns a ZodPipeline
instance.
z.coerce
Zod now provides a more convenient way to coerce primitive values.
const schema = z.coerce.string();
schema.parse("tuna"); // => "tuna"
schema.parse(12); // => "12"
schema.parse(true); // => "true"
During the parsing step, the input is passed through the String()
function, which is a JavaScript built-in for coercing data into strings. Note that the returned schema is a ZodString
instance so you can use all string methods.
z.coerce.string().email().min(5);
All primitive types support coercion.
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)
.catch()
A new schema method .catch()
is now available on all schemas. It can be used to provide a "catchall" value that will be returned in the event of a parsing error.
const schema = z.string().catch("fallback");
schema.parse("kate"); // => "kate"
schema.parse(4); // => "fallback"
The .catch()
method returns a ZodCatch
instance.
z.symbol()
A long-missing hole in Zod's type system is finally filled! Thanks @santosmarco-caribou.
const schema = z.symbol();
schema.parse(Symbol('asdf'));
Relatedly, you can also pass symbols into z.literal()
.
const TUNA = Symbol("tuna");
const schema = z.literal(TUNA);
schema.parse(TUNA); // Symbol(tuna)
schema.parse(Symbol("nottuna")); // Error
z.string().datetime()
A new method has been added to ZodString
to validate ISO datetime strings. Thanks @samchungy!
z.string().datetime();
This method defaults to only allowing UTC datetimes (the ones that end in "Z"
). No timezone offsets are allowed; arbitrary sub-second precision is supported.
const dt = z.string().datetime();
dt.parse("2020-01-01T00:00:00Z"); // 🟢
dt.parse("2020-01-01T00:00:00.123Z"); // 🟢
dt.parse("2020-01-01T00:00:00.123456Z"); // 🟢 (arbitrary precision)
dt.parse("2020-01-01T00:00:00+02:00"); // 🔴 (no offsets allowed)
Offsets can be supported with the offset
parameter.
const a = z.string().datetime({ offset: true });
a.parse("2020-01-01T00:00:00+02:00"); // 🟢 offset allowed
You can additionally constrain the allowable precision
. This specifies the number of digits that should follow the decimal point.
const b = z.string().datetime({ precision: 3 })
b.parse("2020-01-01T00:00:00.123Z"); // 🟢 precision of 3 decimal points
b.parse("2020-01-01T00:00:00Z"); // 🔴 invalid precision
z.number().finite()
Restrict a number schema to finite values. Thanks @igalklebanov.
const schema = z.number().finite();
schema.parse(5); 🟢
schema.parse(Infinity); 🔴
schema.parse(-Infinity); 🔴
What's Changed
- Add
mask
parameter to.required
method by @SrBrahma in #1315 - Added Intersections to TOC by @tmkn in #1450
- [#1468] Fix zod.dev main page cross origin links. by @agrahamg in #1469
- Updates remix-domains library name and description in README by @diogob in #1501
- Removed BRAND from ZodBrand Input definition by @Xetera in #1492
- Add Zodix to readme ecosystem section by @rileytomasek in #1506
- Fix small typos in README by @Yhozen in #1521
- fix typo by @oasido in #1528
- add
fatal
toZodIssue
. by @igalklebanov in #1555 - Fix typo in ERROR_HANDLING.md by @Tsuyoshi84 in #1543
- add
.finite()
@ZodNumber
. by @igalklebanov in #1546 - Fix typing bug hiding errors of nullable composite fields by @tadeokondrak in #1545
- #1227 Feature default on mismatch by @seancrowe in #1537
- fix #1046
.required()
doesn't remove optional flag from the result of.nullish()
. by @igalklebanov in #1542 - add
datetime()
string formats by @samchungy in #1494 - Bump minimatch from 3.0.4 to 3.1.2 by @dependabot in #1558
- Bump minimist from 1.2.5 to 1.2.7 by @dependabot in #1507
- #1171 support for refine, superRefine, transform and lazy in discriminatedUnion by @roblabat in #1290
- branded type as normal argument by @KATT in #1502
- Take
path
parameter into account within.parseAsync()
by @RobinTail in #1513 - Update README.md by @rosnerdev in #1463
- Add
ZodSymbol
by @santosmarco-caribou in #1448 - Fix Minor Typos by @WebDevSimplified in #1624
New Contributors
- @SrBrahma made their first contribution in #1315
- @tmkn made their first contribution in #1450
- @agrahamg made their first contribution in #1469
- @diogob made their first contribution in #1501
- @Xetera made their first contribution in #1492
- @rileytomasek made their first contribution in #1506
- @Yhozen made their first contribution in #1521
- @oasido made their first contribution in #1528
- @igalklebanov made their first contribution in #1555
- @Tsuyoshi84 made their first contribution in #1543
- @tadeokondrak made their first contribution in #1545
- @seancrowe made their first contribution in #1537
- @samchungy made their first contribution in #1494
- @roblabat made their first contribution in #1290
- @KATT made their first contribution in #1502
- @RobinTail made their first contribution in #1513
- @rosnerdev made their first contribution in #1463
- @santosmarco-caribou made their first contribution in #1448
- @WebDevSimplified made their first contribution in #1624
Full Changelog: v3.19.1...v3.20.0