Skip to content

sahilrajput03/learn-zod

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Learn Zod

Quick Links:

Code (autogenerated by auto-docs)

File - 1.ts

import { z } from "zod";
import { deepEqual, equal } from 'assert'

// ❤️ Topics:
//  - Safe (throw error on validation errors) and,
//  - Unsafe parsing via `safeParse()` (without throwing errors on validation errors)
//  - 3 Ways to give custom error message

// * primitive types
//  z.string()
//  z.number()
//  z.bigint();
//  z.boolean();
//  z.symbol();
//  z.undefined();
//  z.null();
// * More
//  z.array()
//  z.string().datetime(),
//  z.string().regex(SIMPLE_MONGODB_ID_REGEX),
//  z.string().datetime().optional(), // Making anything optional
// E.g., 
//      const CarStatusEnumSchema = z.enum(CarStatusEnum).default(CarStatusEnum.AVAILABLE).optional()
//      Note: `optiona()` must occur after default(..) else optional doesn't work. [TESTED]


// * 1. Unsafe Parsing - Throw erron if validation fails.
equal(z.string().parse("tuna"), "tuna")
let e: any
try { z.string().parse(12) } catch (error) { e = error }
equal(e.issues[0].message, 'Invalid input: expected string, received number')

// * 2. Safe Parsing via `safeParse` - No error thrown when validation fails
deepEqual(z.string().safeParse("tuna"), { success: true, data: "tuna" })
// console.log(nameSchema.safeParse(12)); // { success: false; error: `ZodError instance` }

// & We use `safeParse` in below code for all of our below testing
//   because I like to use it in production code as well.

// ❤️ Default error messages at `result.error.issues[*].message` property.
equal(z.string().safeParse('Sahil').data, 'Sahil') // No validation error
equal(z.string().safeParse(123).error?.name, 'ZodError')
equal(z.string().safeParse(123).error?.issues[0].message, 'Invalid input: expected string, received number')
equal(z.string().safeParse(123).error?.issues.map(i => i.message).join(', '), 'Invalid input: expected string, received number')
equal(z.string().safeParse(123).error?.message, `[
  {
    "expected": "string",
    "code": "invalid_type",
    "path": [],
    "message": "Invalid input: expected string, received number"
  }
]`)

// ❤️ CUSTOM ERROR MESSAGE (1) (Source: https://zod.dev/error-customization)
equal(z.string("Please provide string type only.").safeParse('Sahil').data, 'Sahil') // No validation error
equal(z.string("Please provide string type only.").safeParse(123).error?.name, 'ZodError')
equal(
  z.string("Please provide string type only.").safeParse(123).error?.issues[0].message,
  "Please provide string type only.",
)
equal(
  z.string("Please provide string type only.").safeParse(123).error?.message,
  `[
  {
    "expected": "string",
    "code": "invalid_type",
    "path": [],
    "message": "Please provide string type only."
  }
]`
)

// ❤️ CUSTOM ERROR MESSAGE (2) - Another way to pass custom error message is via passing an object:
equal(
  z.string({ error: "Please provide string type only." }).safeParse(123).error?.name,
  'ZodError',
)
equal(
  z.string({ error: "Please provide string type only." }).safeParse(123).error?.message,
  `[
  {
    "expected": "string",
    "code": "invalid_type",
    "path": [],
    "message": "Please provide string type only."
  }
]`,
)
equal(
  z.string({ error: "Please provide string type only." }).safeParse(123).error?.issues[0].message,
  'Please provide string type only.',
)

// ❤️ CUSTOM ERROR MESSAGE (3) - Fro docs: The error param optionally
//      accepts a function. An error customization function is known as an
//      error map in Zod terminology. The error map will run at parse time
//      if a validation error occurs.
equal(z.string({
  error: (issue) => {
    const { code, input, expected } = issue
    equal(issue.expected, 'string')
    equal(issue.code, 'invalid_type')
    equal(issue.input, 123)
    return "Please provide string type only. ";
  }
}).safeParse(123).error?.issues[0].message, "Please provide string type only. ")

File - 2.ts

import { z } from "zod";

// ❤️ Topics:
//  - Accessing nested schema

// User
console.log('\nUser 🚀')
const UserSchema = z.object({
    username: z.string(),
    phone: z.number(),
});
console.log(UserSchema.parse({ username: "Ludwig", phone: 1234 })); // { username: 'Ludwig', phone: 1234 }

const result2 = UserSchema.safeParse({ username: 42, phone: "100" });
if (!result2.success) {
    // console.log("❌ ~ result2:", result2.error) // `ZodError instance`
    console.log("❌ ~ result2.error.issues:", result2.error.issues)
    /**
    [
        {
            expected: 'string',
            code: 'invalid_type',
            path: [ 'username' ],
            message: 'Invalid input: expected string, received number'
        },
        {
            expected: 'number',
            code: 'invalid_type',
            path: [ 'phone' ],
            message: 'Invalid input: expected number, received string'
        }
    ]
     */

    // console.log(z.prettifyError(result.error))
    /**
        ✖ Invalid input: expected string, received number
          → at username
        ✖ Invalid input: expected number, received string
          → at phone
     */
} else {
    result2.data;
}

// ✅ Extract the inferred type
type UserSchema = z.infer<typeof UserSchema>;


// Create new schema with all fields optional
const partialUserSchema = UserSchema.partial();


// ❤️ Accessing a nested schema
const CarSchema = z.object({ name: z.string(), price: z.number() });
console.log(CarSchema.shape.name.parse("BMW")) // "BMW"


//  TODO ❤️ ❤️ ❤️ : https://www.youtube.com/watch?v=9UVPk0Ulm6U

File - 3.ts

import { z } from "zod";

// ❤️ Topics:
//  - Practical mongodb model schema usage.

const SIMPLE_MONGODB_ID_REGEX = /^[a-f\d]{24}$/i;

// From Piyush's Project

// Job
const JobSchema = z.object({
	order: z.string().regex(SIMPLE_MONGODB_ID_REGEX),
	images: z.array(z.object({
		public_id: z.string(),
		url: z.string(),
	})),
	itemName: z.string(),
	costPerUnit: z.number(),
	inventory: z.null(),
	quantity: z.number(),
});
JobSchema.parse({
	order: '5c9cb7138a874f1dcd0d8dcc',
	images: [{
		public_id: 'abc',
		url: 'abc',
	}],
	itemName: 'abc',
	costPerUnit: 0,
	inventory: null,
	quantity: 0,
});
type JobType = z.infer<typeof JobSchema>;


// JobTask
const JobTaskSchema = z.object({
	order: z.string().regex(SIMPLE_MONGODB_ID_REGEX),
	job: z.string().regex(SIMPLE_MONGODB_ID_REGEX),
	jobTaskType: z.number(),
	status: z.number(),
	type: z.string(),
	notes: z.string(),
	user: z.string().regex(SIMPLE_MONGODB_ID_REGEX),
	// `deadline` is optional here because we may want to set this on backend instead of getting from frontend.
	deadline: z.string().datetime().optional(),
});
JobTaskSchema.parse({
	order: '5c9cb7138a874f1dcd0d8dcc',
	job: '5c9cb7138a874f1dcd0d8dcc',
	jobTaskType: 0,
	status: 0,
	type: 'abc',
	notes: 'abc',
	user: '5c9cb7138a874f1dcd0d8dcc',
	deadline: '2023-11-15T13:40:18.365Z',
});
type JobTaskType = z.infer<typeof JobTaskSchema>;


// Order
const OrderSchema = z.object({
	user: z.string().regex(SIMPLE_MONGODB_ID_REGEX),
	paymentInfo: z.object({
		subTotal: z.number(),
		discount: z.number(),
		tax: z.number(),
		totalAmount: z.number(),
		paidAmount: z.number(),
		remainingAmount: z.number(),
	}),
	note: z.string(),
	customer: z.string().regex(SIMPLE_MONGODB_ID_REGEX),
	shippingInfo: z.object({
		name: z.string(),
		phoneNumber: z.number(),
		deadline: z.string().datetime(),
		address: z.string(),
		instructions: z.string(),
	})
});
OrderSchema.parse({
	user: '5c9cb7138a874f1dcd0d8dcc',
	paymentInfo: {
		subTotal: 0,
		discount: 0,
		tax: 0,
		totalAmount: 0,
		paidAmount: 0,
		remainingAmount: 0,
	},
	note: 'abc',
	customer: '5c9cb7138a874f1dcd0d8dcc',
	shippingInfo: {
		name: 'abc',
		phoneNumber: 0,
		deadline: '2023-11-15T13:40:18.365Z',
		address: 'abc',
		instructions: 'abc',
	}
});
type OrderType = z.infer<typeof OrderSchema>;

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors