zod 3.14.0 → 3.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,11 +3,11 @@
3
3
  <h1 align="center">Zod</h1>
4
4
  </p>
5
5
  <p align="center">
6
+ <a href="https://github.com/edgedb/edgedb-js/actions"><img src="https://github.com/colinhacks/zod/actions/workflows/test.yml/badge.svg?event=push&branch=master" alt="Zod CI status" /></a>
6
7
  <a href="https://twitter.com/colinhacks" rel="nofollow"><img src="https://img.shields.io/badge/created%20by-@colinhacks-4BBAAB.svg" alt="Created by Colin McDonnell"></a>
7
8
  <a href="https://opensource.org/licenses/MIT" rel="nofollow"><img src="https://img.shields.io/github/license/colinhacks/zod" alt="License"></a>
8
9
  <a href="https://www.npmjs.com/package/zod" rel="nofollow"><img src="https://img.shields.io/npm/dw/zod.svg" alt="npm"></a>
9
10
  <a href="https://www.npmjs.com/package/zod" rel="nofollow"><img src="https://img.shields.io/github/stars/colinhacks/zod" alt="stars"></a>
10
- <a href="./src/__tests__" rel="nofollow"><img src="./coverage.svg" alt="coverage"></a>
11
11
  <a href="https://discord.gg/KaSRdyX2vc" rel="nofollow"><img src="https://img.shields.io/discord/893487829802418277?label=Discord&logo=discord&logoColor=white" alt="discord server"></a>
12
12
  </p>
13
13
 
@@ -94,8 +94,10 @@ These docs have been translated into [Chinese](./README_ZH.md).
94
94
  - [.promise](#promise)
95
95
  - [.or](#or)
96
96
  - [.and](#and)
97
- - [Type inference](#type-inference)
98
- - [Errors](#errors)
97
+ - [Guides and concepts](#guides-and-concepts)
98
+ - [Type inference](#type-inference)
99
+ - [Writing generic functions](#writing-generic-functions)
100
+ - [Error handling](#error-handling)
99
101
  - [Comparison](#comparison)
100
102
  - [Joi](#joi)
101
103
  - [Yup](#yup)
@@ -241,6 +243,8 @@ There are a growing number of tools that are built atop or support Zod natively!
241
243
  - [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod.
242
244
  - [`graphql-codegen-typescript-validation-schema`](https://github.com/Code-Hex/graphql-codegen-typescript-validation-schema): GraphQL Code Generator plugin to generate form validation schema from your GraphQL schema
243
245
  - [`zod-prisma`](https://github.com/CarterGrimmeisen/zod-prisma): Generate Zod schemas from your Prisma schema.
246
+ - [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod): Create Fastify type providers from Zod schemas
247
+ - [`Supervillain`](https://github.com/Southclaws/supervillain): Generate Zod schemas from your Go structs
244
248
 
245
249
  ### Form integrations
246
250
 
@@ -1687,7 +1691,9 @@ z.object({ name: z.string() }).and(z.object({ age: z.number() })); // { name: st
1687
1691
  z.intersection(z.object({ name: z.string() }), z.object({ age: z.number() }));
1688
1692
  ```
1689
1693
 
1690
- # Type inference
1694
+ # Guides and concepts
1695
+
1696
+ ## Type inference
1691
1697
 
1692
1698
  You can extract the TypeScript type of any schema with `z.infer<typeof mySchema>` .
1693
1699
 
@@ -1716,16 +1722,72 @@ type output = z.output<typeof stringToNumber>; // number
1716
1722
  type inferred = z.infer<typeof stringToNumber>; // number
1717
1723
  ```
1718
1724
 
1719
- # Errors
1725
+ ## Writing generic functions
1726
+
1727
+ When attempting to write a functions that accepts a Zod schemas as an input, it's common to try something like this:
1728
+
1729
+ ```ts
1730
+ function makeSchemaOptional<T>(schema: z.ZodType<T>) {
1731
+ return schema.optional();
1732
+ }
1733
+ ```
1734
+
1735
+ This approach has some issues. The `schema` variable in this function is typed as an instance of `ZodType`, which is an abstract class that all Zod schemas inherit from. This approach loses type information, namely _which subclass_ the input actually is.
1736
+
1737
+ ```ts
1738
+ const arg = makeSchemaOptional(z.string());
1739
+ arg.unwrap();
1740
+ ```
1741
+
1742
+ A better approach is for the generate parameter to refer to _the schema as a whole_.
1743
+
1744
+ ```ts
1745
+ function makeSchemaOptional<T extends z.ZodTypeAny>(schema: T) {
1746
+ return schema.optional();
1747
+ }
1748
+ ```
1749
+
1750
+ > `ZodTypeAny` is just a shorthand for `ZodType<any, any, any>`, a type that is broad enough to match any Zod schema.
1751
+
1752
+ As you can see, `schema` is now fully and properly typed.
1753
+
1754
+ ```ts
1755
+ const arg = makeSchemaOptional(z.string());
1756
+ arg.unwrap(); // ZodString
1757
+ ```
1758
+
1759
+ ### Restricting valid schemas
1760
+
1761
+ The `ZodType` class has three generic parameters.
1762
+
1763
+ ```ts
1764
+ class ZodType<
1765
+ Output,
1766
+ Def extends ZodTypeDef = ZodTypeDef,
1767
+ Input = Output
1768
+ > { ... }
1769
+ ```
1770
+
1771
+ By contraining these in your generic input, you can limit what schemas are allowable as inputs to your function:
1772
+
1773
+ ```ts
1774
+ function makeSchemaOptional<T extends z.ZodType<string>>(schema: T) {
1775
+ return schema.optional();
1776
+ }
1777
+
1778
+ makeSchemaOptional(z.string());
1779
+ // works fine
1780
+
1781
+ makeSchemaOptional(z.number());
1782
+ // Error: 'ZodNumber' is not assignable to parameter of type 'ZodType<string, ZodTypeDef, string>'
1783
+ ```
1784
+
1785
+ ## Error handling
1720
1786
 
1721
1787
  Zod provides a subclass of Error called `ZodError`. ZodErrors contain an `issues` array containing detailed information about the validation problems.
1722
1788
 
1723
1789
  ```ts
1724
- const data = z
1725
- .object({
1726
- name: z.string(),
1727
- })
1728
- .safeParse({ name: 12 });
1790
+ const data = z.object({ name: z.string() }).safeParse({ name: 12 });
1729
1791
 
1730
1792
  if (!data.success) {
1731
1793
  data.error.issues;
@@ -5,11 +5,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const discriminatedUnion_1 = __importDefault(require("./discriminatedUnion"));
7
7
  const object_1 = __importDefault(require("./object"));
8
+ const primitives_1 = __importDefault(require("./primitives"));
8
9
  const realworld_1 = __importDefault(require("./realworld"));
9
10
  const string_1 = __importDefault(require("./string"));
10
11
  const union_1 = __importDefault(require("./union"));
11
12
  for (const suite of [
12
13
  ...realworld_1.default.suites,
14
+ ...primitives_1.default.suites,
13
15
  ...string_1.default.suites,
14
16
  ...object_1.default.suites,
15
17
  ...union_1.default.suites,
@@ -0,0 +1,5 @@
1
+ import Benchmark from "benchmark";
2
+ declare const _default: {
3
+ suites: Benchmark.Suite[];
4
+ };
5
+ export default _default;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const benchmark_1 = __importDefault(require("benchmark"));
7
+ const index_1 = require("../index");
8
+ const enumSuite = new benchmark_1.default.Suite("z.enum");
9
+ const enumSchema = index_1.z.enum(["a", "b", "c"]);
10
+ enumSuite
11
+ .add("valid", () => {
12
+ enumSchema.parse("a");
13
+ })
14
+ .add("invalid", () => {
15
+ try {
16
+ enumSchema.parse("x");
17
+ }
18
+ catch (e) { }
19
+ })
20
+ .on("cycle", (e) => {
21
+ console.log(`z.enum: ${e.target}`);
22
+ });
23
+ const undefinedSuite = new benchmark_1.default.Suite("z.undefined");
24
+ const undefinedSchema = index_1.z.undefined();
25
+ undefinedSuite
26
+ .add("valid", () => {
27
+ undefinedSchema.parse(undefined);
28
+ })
29
+ .add("invalid", () => {
30
+ try {
31
+ undefinedSchema.parse(1);
32
+ }
33
+ catch (e) { }
34
+ })
35
+ .on("cycle", (e) => {
36
+ console.log(`z.undefined: ${e.target}`);
37
+ });
38
+ const literalSuite = new benchmark_1.default.Suite("z.literal");
39
+ const short = "short";
40
+ const bad = "bad";
41
+ const literalSchema = index_1.z.literal("short");
42
+ literalSuite
43
+ .add("valid", () => {
44
+ literalSchema.parse(short);
45
+ })
46
+ .add("invalid", () => {
47
+ try {
48
+ literalSchema.parse(bad);
49
+ }
50
+ catch (e) { }
51
+ })
52
+ .on("cycle", (e) => {
53
+ console.log(`z.literal: ${e.target}`);
54
+ });
55
+ const numberSuite = new benchmark_1.default.Suite("z.number");
56
+ const numberSchema = index_1.z.number().int();
57
+ numberSuite
58
+ .add("valid", () => {
59
+ numberSchema.parse(1);
60
+ })
61
+ .add("invalid type", () => {
62
+ try {
63
+ numberSchema.parse("bad");
64
+ }
65
+ catch (e) { }
66
+ })
67
+ .add("invalid number", () => {
68
+ try {
69
+ numberSchema.parse(0.5);
70
+ }
71
+ catch (e) { }
72
+ })
73
+ .on("cycle", (e) => {
74
+ console.log(`z.number: ${e.target}`);
75
+ });
76
+ exports.default = {
77
+ suites: [enumSuite, undefinedSuite, literalSuite, numberSuite],
78
+ };
@@ -17,6 +17,8 @@ const manual = (str) => {
17
17
  return str;
18
18
  };
19
19
  const stringSchema = index_1.z.string();
20
+ const optionalStringSchema = index_1.z.string().optional();
21
+ const optionalNullableStringSchema = index_1.z.string().optional().nullable();
20
22
  suite
21
23
  .add("empty string", () => {
22
24
  stringSchema.parse(empty);
@@ -26,6 +28,15 @@ suite
26
28
  })
27
29
  .add("long string", () => {
28
30
  stringSchema.parse(long);
31
+ })
32
+ .add("optional string", () => {
33
+ optionalStringSchema.parse(long);
34
+ })
35
+ .add("nullable string", () => {
36
+ optionalNullableStringSchema.parse(long);
37
+ })
38
+ .add("nullable (null) string", () => {
39
+ optionalNullableStringSchema.parse(null);
29
40
  })
30
41
  .add("invalid: null", () => {
31
42
  try {
@@ -38,11 +38,14 @@ export declare type ParsePathComponent = string | number;
38
38
  export declare type ParsePath = ParsePathComponent[];
39
39
  export declare const EMPTY_PATH: ParsePath;
40
40
  export interface ParseContext {
41
+ readonly common: {
42
+ readonly issues: ZodIssue[];
43
+ readonly contextualErrorMap?: ZodErrorMap;
44
+ readonly async: boolean;
45
+ readonly typeCache: Map<any, ZodParsedType> | undefined;
46
+ };
41
47
  readonly path: ParsePath;
42
- readonly issues: ZodIssue[];
43
48
  readonly schemaErrorMap?: ZodErrorMap;
44
- readonly contextualErrorMap?: ZodErrorMap;
45
- readonly async: boolean;
46
49
  readonly parent: ParseContext | null;
47
50
  readonly data: any;
48
51
  readonly parsedType: ZodParsedType;
@@ -97,13 +97,13 @@ function addIssueToContext(ctx, issueData) {
97
97
  data: ctx.data,
98
98
  path: ctx.path,
99
99
  errorMaps: [
100
- ctx.contextualErrorMap,
100
+ ctx.common.contextualErrorMap,
101
101
  ctx.schemaErrorMap,
102
102
  ZodError_1.overrideErrorMap,
103
103
  ZodError_1.defaultErrorMap, // then global default map
104
104
  ].filter((x) => !!x),
105
105
  });
106
- ctx.issues.push(issue);
106
+ ctx.common.issues.push(issue);
107
107
  }
108
108
  exports.addIssueToContext = addIssueToContext;
109
109
  class ParseStatus {