zod 3.8.2 → 3.9.0
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/CHANGELOG.md +56 -0
- package/README.md +277 -251
- package/lib/ZodError.d.ts +10 -4
- package/lib/ZodError.d.ts.map +1 -1
- package/lib/ZodError.js +30 -29
- package/lib/ZodError.js.map +1 -1
- package/lib/benchmarks/index.js +4 -5
- package/lib/benchmarks/index.js.map +1 -1
- package/lib/helpers/errorUtil.d.ts +6 -2
- package/lib/helpers/errorUtil.d.ts.map +1 -1
- package/lib/helpers/parseUtil.d.ts +30 -14
- package/lib/helpers/parseUtil.d.ts.map +1 -1
- package/lib/helpers/parseUtil.js +91 -40
- package/lib/helpers/parseUtil.js.map +1 -1
- package/lib/index.mjs +1 -1
- package/lib/index.mjs.map +1 -1
- package/lib/types.d.ts +204 -145
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +772 -737
- package/lib/types.js.map +1 -1
- package/package.json +6 -3
- package/lib/PseudoPromise.d.ts +0 -7
- package/lib/PseudoPromise.d.ts.map +0 -1
- package/lib/PseudoPromise.js +0 -17
- package/lib/PseudoPromise.js.map +0 -1
package/README.md
CHANGED
|
@@ -29,6 +29,12 @@
|
|
|
29
29
|
- [Literals](#literals)
|
|
30
30
|
- [Strings](#strings)
|
|
31
31
|
- [Numbers](#numbers)
|
|
32
|
+
- [Booleans](#booleans)
|
|
33
|
+
- [Enums](#enums)
|
|
34
|
+
- [Zod enums](#zod-enums)
|
|
35
|
+
- [Native enums](#native-enums)
|
|
36
|
+
- [Optionals](#optionals)
|
|
37
|
+
- [Nullables](#nullables)
|
|
32
38
|
- [Objects](#objects)
|
|
33
39
|
- [.shape](#shape)
|
|
34
40
|
- [.extend](#extend)
|
|
@@ -40,19 +46,14 @@
|
|
|
40
46
|
- [.strict](#strict)
|
|
41
47
|
- [.strip](#strip)
|
|
42
48
|
- [.catchall](#catchall)
|
|
43
|
-
- [Records](#records)
|
|
44
|
-
- [Maps](#maps)
|
|
45
|
-
- [Sets](#sets)
|
|
46
49
|
- [Arrays](#arrays)
|
|
47
50
|
- [.nonempty](#nonempty)
|
|
48
51
|
- [.min/.max/.length](#minmaxlength)
|
|
49
|
-
- [Unions](#unions)
|
|
50
|
-
- [Optionals](#optionals)
|
|
51
|
-
- [Nullables](#nullables)
|
|
52
|
-
- [Enums](#enums)
|
|
53
|
-
- [Zod enums](#zod-enums)
|
|
54
|
-
- [Native enums](#native-enums)
|
|
55
52
|
- [Tuples](#tuples)
|
|
53
|
+
- [Records](#records)
|
|
54
|
+
- [Maps](#maps)
|
|
55
|
+
- [Sets](#sets)
|
|
56
|
+
- [Unions](#unions)
|
|
56
57
|
- [Recursive types](#recursive-types)
|
|
57
58
|
- [JSON type](#json-type)
|
|
58
59
|
- [Cyclical data](#cyclical-objects)
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
- [Instanceof](#instanceof)
|
|
61
62
|
- [Function schemas](#function-schemas)
|
|
62
63
|
- [Preprocess](#preprocess)
|
|
63
|
-
- [
|
|
64
|
+
- [Schema methods](#zodtype-methods-and-properties)
|
|
64
65
|
- [.parse](#parse)
|
|
65
66
|
- [.parseAsync](#parseasync)
|
|
66
67
|
- [.safeParse](#safeparse)
|
|
@@ -229,8 +230,14 @@ import { z } from "zod";
|
|
|
229
230
|
|
|
230
231
|
// creating a schema for strings
|
|
231
232
|
const mySchema = z.string();
|
|
233
|
+
|
|
234
|
+
// parsing
|
|
232
235
|
mySchema.parse("tuna"); // => "tuna"
|
|
233
236
|
mySchema.parse(12); // => throws ZodError
|
|
237
|
+
|
|
238
|
+
// "safe" parsing (doesn't throw error if validation fails)
|
|
239
|
+
mySchema.safeParse("tuna"); // => { success: true; data: "tuna" }
|
|
240
|
+
mySchema.safeParse(12); // => { success: false; error: ZodError }
|
|
234
241
|
```
|
|
235
242
|
|
|
236
243
|
Creating an object schema
|
|
@@ -242,7 +249,7 @@ const User = z.object({
|
|
|
242
249
|
username: z.string(),
|
|
243
250
|
});
|
|
244
251
|
|
|
245
|
-
User.parse({ username:
|
|
252
|
+
User.parse({ username: "Ludwig" });
|
|
246
253
|
|
|
247
254
|
// extract the inferred type
|
|
248
255
|
type User = z.infer<typeof User>;
|
|
@@ -293,6 +300,15 @@ tuna.value; // "tuna"
|
|
|
293
300
|
|
|
294
301
|
## Strings
|
|
295
302
|
|
|
303
|
+
You can customize certain errors when creating a string schema.
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
const name = z.string({
|
|
307
|
+
required: "Name is required",
|
|
308
|
+
invalid: "Invalid name",
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
296
312
|
Zod includes a handful of string-specific validations.
|
|
297
313
|
|
|
298
314
|
```ts
|
|
@@ -316,19 +332,37 @@ z.string().nonempty({ message: "Can't be empty" });
|
|
|
316
332
|
|
|
317
333
|
#### Custom error messages
|
|
318
334
|
|
|
319
|
-
|
|
335
|
+
You can customize certain errors when creating a string schema.
|
|
336
|
+
|
|
337
|
+
```ts
|
|
338
|
+
const name = z.string({
|
|
339
|
+
required_error: "Name is required",
|
|
340
|
+
invalid_type_error: "Name must be a string",
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
When using validation methods, you can pass in an additional argument to provide a custom error message.
|
|
320
345
|
|
|
321
346
|
```ts
|
|
322
347
|
z.string().min(5, { message: "Must be 5 or more characters long" });
|
|
323
348
|
z.string().max(5, { message: "Must be 5 or fewer characters long" });
|
|
324
349
|
z.string().length(5, { message: "Must be exactly 5 characters long" });
|
|
325
|
-
z.string().email({ message: "Invalid email address
|
|
350
|
+
z.string().email({ message: "Invalid email address" });
|
|
326
351
|
z.string().url({ message: "Invalid url" });
|
|
327
352
|
z.string().uuid({ message: "Invalid UUID" });
|
|
328
353
|
```
|
|
329
354
|
|
|
330
355
|
## Numbers
|
|
331
356
|
|
|
357
|
+
You can customize certain error messages when creating a number schema.
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
const age = z.number({
|
|
361
|
+
required_error: "Age is required",
|
|
362
|
+
invalid_type_error: "Age must be a number",
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
332
366
|
Zod includes a handful of number-specific validations.
|
|
333
367
|
|
|
334
368
|
```ts
|
|
@@ -343,6 +377,8 @@ z.number().positive(); // > 0
|
|
|
343
377
|
z.number().nonnegative(); // >= 0
|
|
344
378
|
z.number().negative(); // < 0
|
|
345
379
|
z.number().nonpositive(); // <= 0
|
|
380
|
+
|
|
381
|
+
z.number().multipleOf(5); // Evenly divisible by 5. Alias .step(5)
|
|
346
382
|
```
|
|
347
383
|
|
|
348
384
|
Optionally, you can pass in a second argument to provide a custom error message.
|
|
@@ -351,6 +387,183 @@ Optionally, you can pass in a second argument to provide a custom error message.
|
|
|
351
387
|
z.number().lte(5, { message: "this👏is👏too👏big" });
|
|
352
388
|
```
|
|
353
389
|
|
|
390
|
+
## Booleans
|
|
391
|
+
|
|
392
|
+
You can customize certain error messages when creating a boolean schema.
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
const isActive = z.boolean({
|
|
396
|
+
required_error: "isActive is required",
|
|
397
|
+
invalid_type_error: "isActive must be a boolean",
|
|
398
|
+
});
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## Enums
|
|
402
|
+
|
|
403
|
+
There are two ways to define enums in Zod.
|
|
404
|
+
|
|
405
|
+
### Zod enums
|
|
406
|
+
|
|
407
|
+
```ts
|
|
408
|
+
const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
|
|
409
|
+
type FishEnum = z.infer<typeof FishEnum>;
|
|
410
|
+
// 'Salmon' | 'Tuna' | 'Trout'
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
You must pass the array of values directly into `z.enum()`. Alternatively, use `as const` to define your enum values as a tuple of strings. See the [const assertion docs](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions) for details.
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
const VALUES = ["Salmon", "Tuna", "Trout"] as const;
|
|
417
|
+
const FishEnum = z.enum(VALUES);
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
This is not allowed:
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
const fish = ["Salmon", "Tuna", "Trout"];
|
|
424
|
+
const FishEnum = z.enum(fish);
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
In that case, the inferred type of `fish` is simply `string[]`, so Zod isn't able to infer the individual enum elements.
|
|
428
|
+
|
|
429
|
+
**Autocompletion**
|
|
430
|
+
|
|
431
|
+
To get autocompletion with a Zod enum, use the `.enum` property of your schema:
|
|
432
|
+
|
|
433
|
+
```ts
|
|
434
|
+
FishEnum.enum.Salmon; // => autocompletes
|
|
435
|
+
|
|
436
|
+
FishEnum.enum;
|
|
437
|
+
/*
|
|
438
|
+
=> {
|
|
439
|
+
Salmon: "Salmon",
|
|
440
|
+
Tuna: "Tuna",
|
|
441
|
+
Trout: "Trout",
|
|
442
|
+
}
|
|
443
|
+
*/
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
You can also retrieve the list of options as a tuple with the `.options` property:
|
|
447
|
+
|
|
448
|
+
```ts
|
|
449
|
+
FishEnum.options; // ["Salmon", "Tuna", "Trout"]);
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Native enums
|
|
453
|
+
|
|
454
|
+
Zod enums are the recommended approach to defining and validating enums. But if you need to validate against an enum from a third-party library (or you don't want to rewrite your existing enums) you can use `z.nativeEnum()` .
|
|
455
|
+
|
|
456
|
+
**Numeric enums**
|
|
457
|
+
|
|
458
|
+
```ts
|
|
459
|
+
enum Fruits {
|
|
460
|
+
Apple,
|
|
461
|
+
Banana,
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const FruitEnum = z.nativeEnum(Fruits);
|
|
465
|
+
type FruitEnum = z.infer<typeof FruitEnum>; // Fruits
|
|
466
|
+
|
|
467
|
+
FruitEnum.parse(Fruits.Apple); // passes
|
|
468
|
+
FruitEnum.parse(Fruits.Banana); // passes
|
|
469
|
+
FruitEnum.parse(0); // passes
|
|
470
|
+
FruitEnum.parse(1); // passes
|
|
471
|
+
FruitEnum.parse(3); // fails
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**String enums**
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
enum Fruits {
|
|
478
|
+
Apple = "apple",
|
|
479
|
+
Banana = "banana",
|
|
480
|
+
Cantaloupe, // you can mix numerical and string enums
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const FruitEnum = z.nativeEnum(Fruits);
|
|
484
|
+
type FruitEnum = z.infer<typeof FruitEnum>; // Fruits
|
|
485
|
+
|
|
486
|
+
FruitEnum.parse(Fruits.Apple); // passes
|
|
487
|
+
FruitEnum.parse(Fruits.Cantaloupe); // passes
|
|
488
|
+
FruitEnum.parse("apple"); // passes
|
|
489
|
+
FruitEnum.parse("banana"); // passes
|
|
490
|
+
FruitEnum.parse(0); // passes
|
|
491
|
+
FruitEnum.parse("Cantaloupe"); // fails
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**Const enums**
|
|
495
|
+
|
|
496
|
+
The `.nativeEnum()` function works for `as const` objects as well. ⚠️ `as const` required TypeScript 3.4+!
|
|
497
|
+
|
|
498
|
+
```ts
|
|
499
|
+
const Fruits = {
|
|
500
|
+
Apple: "apple",
|
|
501
|
+
Banana: "banana",
|
|
502
|
+
Cantaloupe: 3,
|
|
503
|
+
} as const;
|
|
504
|
+
|
|
505
|
+
const FruitEnum = z.nativeEnum(Fruits);
|
|
506
|
+
type FruitEnum = z.infer<typeof FruitEnum>; // "apple" | "banana" | 3
|
|
507
|
+
|
|
508
|
+
FruitEnum.parse("apple"); // passes
|
|
509
|
+
FruitEnum.parse("banana"); // passes
|
|
510
|
+
FruitEnum.parse(3); // passes
|
|
511
|
+
FruitEnum.parse("Cantaloupe"); // fails
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
## Optionals
|
|
515
|
+
|
|
516
|
+
You can make any schema optional with `z.optional()`:
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
const schema = z.optional(z.string());
|
|
520
|
+
|
|
521
|
+
schema.parse(undefined); // => returns undefined
|
|
522
|
+
type A = z.infer<typeof A>; // string | undefined
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
You can make an existing schema optional with the `.optional()` method:
|
|
526
|
+
|
|
527
|
+
```ts
|
|
528
|
+
const user = z.object({
|
|
529
|
+
username: z.string().optional(),
|
|
530
|
+
});
|
|
531
|
+
type C = z.infer<typeof C>; // { username?: string | undefined };
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
#### `.unwrap`
|
|
535
|
+
|
|
536
|
+
```ts
|
|
537
|
+
const stringSchema = z.string();
|
|
538
|
+
const optionalString = stringSchema.optional();
|
|
539
|
+
optionalString.unwrap() === stringSchema; // true
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## Nullables
|
|
543
|
+
|
|
544
|
+
Similarly, you can create nullable types like so:
|
|
545
|
+
|
|
546
|
+
```ts
|
|
547
|
+
const nullableString = z.nullable(z.string());
|
|
548
|
+
nullableString.parse("asdf"); // => "asdf"
|
|
549
|
+
nullableString.parse(null); // => null
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
You can make an existing schema nullable with the `nullable` method:
|
|
553
|
+
|
|
554
|
+
```ts
|
|
555
|
+
const E = z.string().nullable(); // equivalent to D
|
|
556
|
+
type E = z.infer<typeof D>; // string | null
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
#### `.unwrap`
|
|
560
|
+
|
|
561
|
+
```ts
|
|
562
|
+
const stringSchema = z.string();
|
|
563
|
+
const nullableString = stringSchema.nullable();
|
|
564
|
+
nullableString.unwrap() === stringSchema; // true
|
|
565
|
+
```
|
|
566
|
+
|
|
354
567
|
## Objects
|
|
355
568
|
|
|
356
569
|
```ts
|
|
@@ -442,16 +655,31 @@ Starting from this object:
|
|
|
442
655
|
|
|
443
656
|
```ts
|
|
444
657
|
const user = z.object({
|
|
658
|
+
email: z.string()
|
|
445
659
|
username: z.string(),
|
|
446
660
|
});
|
|
447
|
-
// { username: string }
|
|
661
|
+
// { email: string; username: string }
|
|
448
662
|
```
|
|
449
663
|
|
|
450
664
|
We can create a partial version:
|
|
451
665
|
|
|
452
666
|
```ts
|
|
453
667
|
const partialUser = user.partial();
|
|
454
|
-
// { username?: string | undefined }
|
|
668
|
+
// { email?: string | undefined; username?: string | undefined }
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
You can also specify which properties to make optional:
|
|
672
|
+
|
|
673
|
+
```ts
|
|
674
|
+
const optionalEmail = user.partial({
|
|
675
|
+
email: true,
|
|
676
|
+
});
|
|
677
|
+
/*
|
|
678
|
+
{
|
|
679
|
+
email?: string | undefined;
|
|
680
|
+
username: string
|
|
681
|
+
}
|
|
682
|
+
*/
|
|
455
683
|
```
|
|
456
684
|
|
|
457
685
|
### `.deepPartial`
|
|
@@ -608,6 +836,23 @@ z.string().array().length(5); // must contain 5 items exactly
|
|
|
608
836
|
|
|
609
837
|
Unlike `.nonempty()` these methods do not change the inferred type.
|
|
610
838
|
|
|
839
|
+
## Tuples
|
|
840
|
+
|
|
841
|
+
Unlike arrays, tuples have a fixed number of elements and each element can have a different type.
|
|
842
|
+
|
|
843
|
+
```ts
|
|
844
|
+
const athleteSchema = z.tuple([
|
|
845
|
+
z.string(), // name
|
|
846
|
+
z.number(), // jersey number
|
|
847
|
+
z.object({
|
|
848
|
+
pointsScored: z.number(),
|
|
849
|
+
}), // statistics
|
|
850
|
+
]);
|
|
851
|
+
|
|
852
|
+
type Athlete = z.infer<typeof athleteSchema>;
|
|
853
|
+
// type Athlete = [string, number, { pointsScored: number }]
|
|
854
|
+
```
|
|
855
|
+
|
|
611
856
|
## Unions
|
|
612
857
|
|
|
613
858
|
Zod includes a built-in `z.union` method for composing "OR" types.
|
|
@@ -627,79 +872,6 @@ For convenience, you can also use the `.or` method:
|
|
|
627
872
|
const stringOrNumber = z.string().or(z.number());
|
|
628
873
|
```
|
|
629
874
|
|
|
630
|
-
## Optionals
|
|
631
|
-
|
|
632
|
-
You can make any schema optional with `z.optional()`:
|
|
633
|
-
|
|
634
|
-
```ts
|
|
635
|
-
const schema = z.optional(z.string());
|
|
636
|
-
|
|
637
|
-
schema.parse(undefined); // => returns undefined
|
|
638
|
-
type A = z.infer<typeof A>; // string | undefined
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
You can make an existing schema optional with the `.optional()` method:
|
|
642
|
-
|
|
643
|
-
```ts
|
|
644
|
-
const user = z.object({
|
|
645
|
-
username: z.string().optional(),
|
|
646
|
-
});
|
|
647
|
-
type C = z.infer<typeof C>; // { username?: string | undefined };
|
|
648
|
-
```
|
|
649
|
-
|
|
650
|
-
#### `.unwrap`
|
|
651
|
-
|
|
652
|
-
```ts
|
|
653
|
-
const stringSchema = z.string();
|
|
654
|
-
const optionalString = stringSchema.optional();
|
|
655
|
-
optionalString.unwrap() === stringSchema; // true
|
|
656
|
-
```
|
|
657
|
-
|
|
658
|
-
## Nullables
|
|
659
|
-
|
|
660
|
-
Similarly, you can create nullable types like so:
|
|
661
|
-
|
|
662
|
-
```ts
|
|
663
|
-
const nullableString = z.nullable(z.string());
|
|
664
|
-
nullableString.parse("asdf"); // => "asdf"
|
|
665
|
-
nullableString.parse(null); // => null
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
You can make an existing schema nullable with the `nullable` method:
|
|
669
|
-
|
|
670
|
-
```ts
|
|
671
|
-
const E = z.string().nullable(); // equivalent to D
|
|
672
|
-
type E = z.infer<typeof D>; // string | null
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
#### `.unwrap`
|
|
676
|
-
|
|
677
|
-
```ts
|
|
678
|
-
const stringSchema = z.string();
|
|
679
|
-
const nullableString = stringSchema.nullable();
|
|
680
|
-
nullableString.unwrap() === stringSchema; // true
|
|
681
|
-
```
|
|
682
|
-
|
|
683
|
-
<!--
|
|
684
|
-
|
|
685
|
-
``` ts
|
|
686
|
-
/* Custom Union Types */
|
|
687
|
-
|
|
688
|
-
const F = z
|
|
689
|
-
.union([z.string(), z.number(), z.boolean()])
|
|
690
|
-
.optional()
|
|
691
|
-
.nullable();
|
|
692
|
-
|
|
693
|
-
F.parse('tuna'); // => tuna
|
|
694
|
-
F.parse(42); // => 42
|
|
695
|
-
F.parse(true); // => true
|
|
696
|
-
F.parse(undefined); // => undefined
|
|
697
|
-
F.parse(null); // => null
|
|
698
|
-
F.parse({}); // => throws Error!
|
|
699
|
-
|
|
700
|
-
type F = z.infer<typeof F>; // string | number | boolean | undefined | null;
|
|
701
|
-
``` -->
|
|
702
|
-
|
|
703
875
|
## Records
|
|
704
876
|
|
|
705
877
|
Record schemas are used to validate types such as `{ [k: string]: number }`.
|
|
@@ -765,134 +937,6 @@ type numberSet = z.infer<typeof numberSet>;
|
|
|
765
937
|
// Set<number>
|
|
766
938
|
```
|
|
767
939
|
|
|
768
|
-
## Enums
|
|
769
|
-
|
|
770
|
-
There are two ways to define enums in Zod.
|
|
771
|
-
|
|
772
|
-
### Zod enums
|
|
773
|
-
|
|
774
|
-
<!-- An enum is just a union of string literals, so you _could_ define an enum like this:
|
|
775
|
-
|
|
776
|
-
```ts
|
|
777
|
-
const FishEnum = z.union([
|
|
778
|
-
z.literal("Salmon"),
|
|
779
|
-
z.literal("Tuna"),
|
|
780
|
-
z.literal("Trout"),
|
|
781
|
-
]);
|
|
782
|
-
|
|
783
|
-
FishEnum.parse("Salmon"); // => "Salmon"
|
|
784
|
-
FishEnum.parse("Flounder"); // => throws
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
For convenience Zod provides a built-in `z.enum()` function. Here's is the equivalent code: -->
|
|
788
|
-
|
|
789
|
-
```ts
|
|
790
|
-
const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
|
|
791
|
-
type FishEnum = z.infer<typeof FishEnum>;
|
|
792
|
-
// 'Salmon' | 'Tuna' | 'Trout'
|
|
793
|
-
```
|
|
794
|
-
|
|
795
|
-
You must pass the array of values directly into `z.enum()`. Alternatively, use `as const` to define your enum values as a tuple of strings. See the [const assertion docs](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions) for details.
|
|
796
|
-
|
|
797
|
-
```ts
|
|
798
|
-
const VALUES = ["Salmon", "Tuna", "Trout"] as const;
|
|
799
|
-
const FishEnum = z.enum(VALUES);
|
|
800
|
-
```
|
|
801
|
-
|
|
802
|
-
This is not allowed:
|
|
803
|
-
|
|
804
|
-
```ts
|
|
805
|
-
const fish = ["Salmon", "Tuna", "Trout"];
|
|
806
|
-
const FishEnum = z.enum(fish);
|
|
807
|
-
```
|
|
808
|
-
|
|
809
|
-
In that case, the inferred type of `fish` is simply `string[]`, so Zod isn't able to infer the individual enum elements.
|
|
810
|
-
|
|
811
|
-
**Autocompletion**
|
|
812
|
-
|
|
813
|
-
To get autocompletion with a Zod enum, use the `.enum` property of your schema:
|
|
814
|
-
|
|
815
|
-
```ts
|
|
816
|
-
FishEnum.enum.Salmon; // => autocompletes
|
|
817
|
-
|
|
818
|
-
FishEnum.enum;
|
|
819
|
-
/*
|
|
820
|
-
=> {
|
|
821
|
-
Salmon: "Salmon",
|
|
822
|
-
Tuna: "Tuna",
|
|
823
|
-
Trout: "Trout",
|
|
824
|
-
}
|
|
825
|
-
*/
|
|
826
|
-
```
|
|
827
|
-
|
|
828
|
-
You can also retrieve the list of options as a tuple with the `.options` property:
|
|
829
|
-
|
|
830
|
-
```ts
|
|
831
|
-
FishEnum.options; // ["Salmon", "Tuna", "Trout"]);
|
|
832
|
-
```
|
|
833
|
-
|
|
834
|
-
### Native enums
|
|
835
|
-
|
|
836
|
-
Zod enums are the recommended approach to defining and validating enums. But if you need to validate against an enum from a third-party library (or you don't want to rewrite your existing enums) you can use `z.nativeEnum()` .
|
|
837
|
-
|
|
838
|
-
**Numeric enums**
|
|
839
|
-
|
|
840
|
-
```ts
|
|
841
|
-
enum Fruits {
|
|
842
|
-
Apple,
|
|
843
|
-
Banana,
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
const FruitEnum = z.nativeEnum(Fruits);
|
|
847
|
-
type FruitEnum = z.infer<typeof FruitEnum>; // Fruits
|
|
848
|
-
|
|
849
|
-
FruitEnum.parse(Fruits.Apple); // passes
|
|
850
|
-
FruitEnum.parse(Fruits.Banana); // passes
|
|
851
|
-
FruitEnum.parse(0); // passes
|
|
852
|
-
FruitEnum.parse(1); // passes
|
|
853
|
-
FruitEnum.parse(3); // fails
|
|
854
|
-
```
|
|
855
|
-
|
|
856
|
-
**String enums**
|
|
857
|
-
|
|
858
|
-
```ts
|
|
859
|
-
enum Fruits {
|
|
860
|
-
Apple = "apple",
|
|
861
|
-
Banana = "banana",
|
|
862
|
-
Cantaloupe, // you can mix numerical and string enums
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
const FruitEnum = z.nativeEnum(Fruits);
|
|
866
|
-
type FruitEnum = z.infer<typeof FruitEnum>; // Fruits
|
|
867
|
-
|
|
868
|
-
FruitEnum.parse(Fruits.Apple); // passes
|
|
869
|
-
FruitEnum.parse(Fruits.Cantaloupe); // passes
|
|
870
|
-
FruitEnum.parse("apple"); // passes
|
|
871
|
-
FruitEnum.parse("banana"); // passes
|
|
872
|
-
FruitEnum.parse(0); // passes
|
|
873
|
-
FruitEnum.parse("Cantaloupe"); // fails
|
|
874
|
-
```
|
|
875
|
-
|
|
876
|
-
**Const enums**
|
|
877
|
-
|
|
878
|
-
The `.nativeEnum()` function works for `as const` objects as well. ⚠️ `as const` required TypeScript 3.4+!
|
|
879
|
-
|
|
880
|
-
```ts
|
|
881
|
-
const Fruits = {
|
|
882
|
-
Apple: "apple",
|
|
883
|
-
Banana: "banana",
|
|
884
|
-
Cantaloupe: 3,
|
|
885
|
-
} as const;
|
|
886
|
-
|
|
887
|
-
const FruitEnum = z.nativeEnum(Fruits);
|
|
888
|
-
type FruitEnum = z.infer<typeof FruitEnum>; // "apple" | "banana" | 3
|
|
889
|
-
|
|
890
|
-
FruitEnum.parse("apple"); // passes
|
|
891
|
-
FruitEnum.parse("banana"); // passes
|
|
892
|
-
FruitEnum.parse(3); // passes
|
|
893
|
-
FruitEnum.parse("Cantaloupe"); // fails
|
|
894
|
-
```
|
|
895
|
-
|
|
896
940
|
## Intersections
|
|
897
941
|
|
|
898
942
|
<!-- > ⚠️ Intersections are deprecated. If you are trying to merge objects, use the `.merge` method instead. -->
|
|
@@ -943,23 +987,6 @@ type Teacher = z.infer<typeof Teacher>;
|
|
|
943
987
|
// { id:string; name:string };
|
|
944
988
|
``` -->
|
|
945
989
|
|
|
946
|
-
## Tuples
|
|
947
|
-
|
|
948
|
-
Unlike arrays, tuples have a fixed number of elements and each element can have a different type.
|
|
949
|
-
|
|
950
|
-
```ts
|
|
951
|
-
const athleteSchema = z.tuple([
|
|
952
|
-
z.string(), // name
|
|
953
|
-
z.number(), // jersey number
|
|
954
|
-
z.object({
|
|
955
|
-
pointsScored: z.number(),
|
|
956
|
-
}), // statistics
|
|
957
|
-
]);
|
|
958
|
-
|
|
959
|
-
type Athlete = z.infer<typeof athleteSchema>;
|
|
960
|
-
// type Athlete = [string, number, { pointsScored: number }]
|
|
961
|
-
```
|
|
962
|
-
|
|
963
990
|
## Recursive types
|
|
964
991
|
|
|
965
992
|
You can define a recursive schema in Zod, but because of a limitation of TypeScript, their type can't be statically inferred. Instead you'll need to define the type definition manually, and provide it to Zod as a "type hint".
|
|
@@ -1167,9 +1194,9 @@ myFunction; // (arg: string)=>number[]
|
|
|
1167
1194
|
|
|
1168
1195
|
## Preprocess
|
|
1169
1196
|
|
|
1170
|
-
Typically Zod operates under a "parse
|
|
1197
|
+
Typically Zod operates under a "parse then transform" paradigm. Zod validates the input first, then passes it through a chain of transformation functions. (For more information about transforms, read the [.transform docs](#transform).)
|
|
1171
1198
|
|
|
1172
|
-
But sometimes you want to apply some
|
|
1199
|
+
But sometimes you want to apply some transform to the input _before_ parsing happens. A common use case: type coercion. Zod enables this with the `z.preprocess()`.
|
|
1173
1200
|
|
|
1174
1201
|
```ts
|
|
1175
1202
|
const castToString = z.preprocess((val) => String(val), z.string());
|
|
@@ -1410,11 +1437,11 @@ const stringToNumber = z.string().transform((val) => myString.length);
|
|
|
1410
1437
|
stringToNumber.parse("string"); // => 6
|
|
1411
1438
|
```
|
|
1412
1439
|
|
|
1413
|
-
> ⚠️
|
|
1440
|
+
> ⚠️ Transform functions must not throw. Make sure to use refinements before the transform to make sure the input can be parsed by the transform.
|
|
1414
1441
|
|
|
1415
1442
|
#### Chaining order
|
|
1416
1443
|
|
|
1417
|
-
Note that `stringToNumber` above is an instance of the `ZodEffects` subclass. It is NOT an instance of `ZodString`. If you want to use the built-in methods of `ZodString` (e.g. `.email()`) you must apply those methods _before_ any
|
|
1444
|
+
Note that `stringToNumber` above is an instance of the `ZodEffects` subclass. It is NOT an instance of `ZodString`. If you want to use the built-in methods of `ZodString` (e.g. `.email()`) you must apply those methods _before_ any transforms.
|
|
1418
1445
|
|
|
1419
1446
|
```ts
|
|
1420
1447
|
const emailToDomain = z
|
|
@@ -1435,25 +1462,24 @@ z.string()
|
|
|
1435
1462
|
.refine((val) => val > 25);
|
|
1436
1463
|
```
|
|
1437
1464
|
|
|
1438
|
-
#### Async
|
|
1465
|
+
#### Async transforms
|
|
1439
1466
|
|
|
1440
|
-
|
|
1467
|
+
Transforms can also be async.
|
|
1441
1468
|
|
|
1442
1469
|
```ts
|
|
1443
|
-
const IdToUser = z
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
(
|
|
1470
|
+
const IdToUser = z
|
|
1471
|
+
.string()
|
|
1472
|
+
.uuid()
|
|
1473
|
+
.transform(async (id) => {
|
|
1447
1474
|
return await getUserById(id);
|
|
1448
|
-
}
|
|
1449
|
-
);
|
|
1475
|
+
});
|
|
1450
1476
|
```
|
|
1451
1477
|
|
|
1452
|
-
> ⚠️ If your schema contains asynchronous
|
|
1478
|
+
> ⚠️ If your schema contains asynchronous transforms, you must use .parseAsync() or .safeParseAsync() to parse data. Otherwise Zod will throw an error.
|
|
1453
1479
|
|
|
1454
1480
|
### `.default`
|
|
1455
1481
|
|
|
1456
|
-
You can use
|
|
1482
|
+
You can use transforms to implement the concept of "default values" in Zod.
|
|
1457
1483
|
|
|
1458
1484
|
```ts
|
|
1459
1485
|
const stringWithDefault = z.string().default("tuna");
|
|
@@ -1539,7 +1565,7 @@ z.union([z.string(), z.number()]);
|
|
|
1539
1565
|
|
|
1540
1566
|
### `.and`
|
|
1541
1567
|
|
|
1542
|
-
A convenience method for creating
|
|
1568
|
+
A convenience method for creating intersection types.
|
|
1543
1569
|
|
|
1544
1570
|
```ts
|
|
1545
1571
|
z.object({ name: z.string() }).and(z.object({ age: z.number() })); // { name: string } & { age: number }
|
|
@@ -1562,7 +1588,7 @@ const u: A = "asdf"; // compiles
|
|
|
1562
1588
|
|
|
1563
1589
|
#### What about transforms?
|
|
1564
1590
|
|
|
1565
|
-
In reality each Zod schema
|
|
1591
|
+
In reality each Zod schema internally tracks **two** types: an input and an output. For most schemas (e.g. `z.string()`) these two are the same. But once you add transforms into the mix, these two values can diverge. For instance `z.string().transform(val => val.length)` has an input of `string` and an output of `number`.
|
|
1566
1592
|
|
|
1567
1593
|
You can separately extract the input and output types like so:
|
|
1568
1594
|
|
|
@@ -1648,7 +1674,7 @@ Tuples
|
|
|
1648
1674
|
Recursive Types
|
|
1649
1675
|
Function Schemas
|
|
1650
1676
|
|
|
1651
|
-
<abbr title="For instance, Yup allows
|
|
1677
|
+
<abbr title="For instance, Yup allows custom error messages with the syntax yup.number().min(5, 'Number must be more than 5!')">Validation Messages</abbr>
|
|
1652
1678
|
Immutable instances
|
|
1653
1679
|
Type Guards
|
|
1654
1680
|
Validity Checking
|
|
@@ -1681,7 +1707,7 @@ Yup is a full-featured library that was implemented first in vanilla JS, and lat
|
|
|
1681
1707
|
|
|
1682
1708
|
Differences
|
|
1683
1709
|
|
|
1684
|
-
- Supports
|
|
1710
|
+
- Supports casting and transforms
|
|
1685
1711
|
- All object fields are optional by default
|
|
1686
1712
|
- Missing object methods: (partial, deepPartial)
|
|
1687
1713
|
<!-- - Missing nonempty arrays with proper typing (`[T, ...T[]]`) -->
|