Elysia Tools

Browse tools, examples, visual explainers, and topic guides from one clear workspace.

Top Categories

Hubs

Language
ZHESPTRUFRDEEN

Elysia Tools

Navigation

Validation Libraries

Zod Schema Validation

Zod TypeScript-first schema validation examples including primitives, objects, arrays, transforms, custom validators, and error handling

Samples

Entries inside this sample collection

CodetypescriptSimple

Zod Basics and Primitives

Fundamental Zod schema validation including primitive types, basic validation, and simple transforms

Difficulty

3/10

Estimated time

25 min

Tags

zod, validation, typescript, runtime

Prerequisites

TypeScript basics, JavaScript

typescript
// Zod Basics and Primitive Types Example

import { z } from 'zod';

// 1. Primitive Types
const stringSchema = z.string();
const numberSchema = z.number();
const booleanSchema = z.boolean();
const dateSchema = z.date();
const undefinedSchema = z.undefined();
const nullSchema = z.null();

// Test primitive validation
console.log(stringSchema.parse('hello')); // ✅ 'hello'
console.log(numberSchema.parse(42)); // ✅ 42
console.log(booleanSchema.parse(true)); // ✅ true
console.log(dateSchema.parse(new Date())); // ✅ Date object
console.log(undefinedSchema.parse(undefined)); // ✅ undefined
console.log(nullSchema.parse(null)); // ✅ null

// 2. Type Constraints
const minStringLength = z.string().min(5);
const maxStringLength = z.string().max(10);
const emailRegex = z.string().email();
const urlRegex = z.string().url();

console.log(minStringLength.parse('hello world')); // ✅
console.log(maxStringLength.parse('short')); // ✅
console.log(emailRegex.parse('[email protected]')); // ✅
console.log(urlRegex.parse('https://example.com')); // ✅

// 3. Number Constraints
const positiveNumber = z.number().positive();
const nonNegativeNumber = z.number().nonnegative();
const maxNumber = z.number().max(100);
const minNumber = z.number().min(18);
const intNumber = z.number().int();

console.log(positiveNumber.parse(10)); // ✅
console.log(nonNegativeNumber.parse(0)); // ✅
console.log(maxNumber.parse(50)); // ✅
console.log(minNumber.parse(25)); // ✅
console.log(intNumber.parse(42)); // ✅

// 4. Optional and Nullable Types
const optionalString = z.string().optional();
const nullableString = z.string().nullable();
const optionalOrNullableString = z.string().optional().nullable();

console.log(optionalString.parse('hello')); // ✅ 'hello'
console.log(optionalString.parse(undefined)); // ✅ undefined
console.log(nullableString.parse(null)); // ✅ null
console.log(nullableString.parse('hello')); // ✅ 'hello'

// 5. Default Values
const stringWithDefault = z.string().default('default value');
const optionalStringWithDefault = z.string().optional().default('optional default');

console.log(stringWithDefault.parse(undefined)); // ✅ 'default value'
console.log(optionalStringWithDefault.parse(undefined)); // ✅ 'optional default'

// 6. Enum-like Values
const directionSchema = z.enum(['north', 'south', 'east', 'west']);
const brandSchema = z.enum(['Nike', 'Adidas', 'Puma', 'Reebok']);

console.log(directionSchema.parse('north')); // ✅ 'north'
console.log(brandSchema.parse('Nike')); // ✅ 'Nike'

// 7. Literal Types
const trueSchema = z.literal(true);
const numberLiteral = z.literal(42);
const stringLiteral = z.literal('specific-value');

console.log(trueSchema.parse(true)); // ✅ true
console.log(numberLiteral.parse(42)); // ✅ 42
console.log(stringLiteral.parse('specific-value')); // ✅ 'specific-value'

// 8. Union Types
const stringOrNumber = z.union([z.string(), z.number()]);
const colorSchema = z.union([z.literal('red'), z.literal('green'), z.literal('blue')]);

console.log(stringOrNumber.parse('hello')); // ✅ 'hello'
console.log(stringOrNumber.parse(42)); // ✅ 42
console.log(colorSchema.parse('red')); // ✅ 'red'

// 9. Intersection Types
const personName = z.object({
  firstName: z.string(),
  lastName: z.string(),
});

const personAge = z.object({
  age: z.number().positive(),
});

const personWithDetails = z.intersection(personName, personAge);

console.log(personWithDetails.parse({
  firstName: 'John',
  lastName: 'Doe',
  age: 30
})); // ✅

// 10. Safe Parsing
const result = stringSchema.safeParse(123);
if (result.success) {
  console.log('Valid:', result.data);
} else {
  console.log('Invalid:', result.error);
}

// 11. Custom Validation
const customEmailSchema = z.string().email().refine((email) => {
  return email.endsWith('@company.com');
}, {
  message: 'Email must be from @company.com domain',
  path: ['domain']
});

try {
  customEmailSchema.parse('[email protected]'); // ✅
  customEmailSchema.parse('[email protected]'); // ❌
} catch (error) {
  console.error('Custom validation error:', error);
}

// 12. Transformations
const stringToNumber = z.string().transform((str) => parseInt(str, 10));
const uppercaseString = z.string().transform((str) => str.toUpperCase());
const trimmedString = z.string().transform((str) => str.trim());

const transformedNumber = stringToNumber.parse('123'); // ✅ 123 (number)
const transformedUpper = uppercaseString.parse('hello'); // ✅ 'HELLO'
const transformedTrim = trimmedString.parse('  hello  '); // ✅ 'hello'

// 13. Preprocessing and Postprocessing
const preprocessSchema = z.string().transform((str) => str.trim().toLowerCase());

const postprocessSchema = z.string().transform((str) => {
  return {
    original: str,
    length: str.length,
    uppercase: str.toUpperCase()
  };
});

const preprocessResult = preprocessSchema.parse('  HELLO  '); // ✅ 'hello'
const postprocessResult = postprocessSchema.parse('hello'); // ✅ { original: 'hello', length: 5, uppercase: 'HELLO' }

// 14. Pipeline Transformations
const dateToTimestamp = z.date().transform((date) => date.getTime());
const timestampToDate = z.number().transform((timestamp) => new Date(timestamp));

const timestamp = dateToTimestamp.parse(new Date()); // ✅ timestamp (number)
const date = timestampToDate.parse(Date.now()); // ✅ Date object

// 15. Error Customization
const customErrorSchema = z.string({
  errorMap: (issue, ctx) => {
    if (issue.code === z.ZodIssueCode.invalid_string) {
      return { message: 'Custom error message for invalid string' };
    }
    if (issue.code === z.ZodIssueCode.too_small) {
      return { message: 'String is too short!' };
    }
    return { message: ctx.defaultError };
  },
}).min(5);

try {
  customErrorSchema.parse('abc'); // ❌ Custom error
} catch (error) {
  console.log('Custom error message');
}

// 16. Advanced Primitive Examples

// Password validation with multiple requirements
const passwordSchema = z.string()
  .min(8, 'Password must be at least 8 characters')
  .max(100, 'Password must be less than 100 characters')
  .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
  .regex(/[a-z]/, 'Password must contain at least one lowercase letter')
  .regex(/[0-9]/, 'Password must contain at least one number')
  .regex(/[^A-Za-z0-9]/, 'Password must contain at least one special character');

// Username validation
const usernameSchema = z.string()
  .min(3, 'Username must be at least 3 characters')
  .max(20, 'Username must be less than 20 characters')
  .regex(/^[a-zA-Z0-9_]+$/, 'Username can only contain letters, numbers, and underscores')
  .refine((username) => !username.startsWith('_'), {
    message: 'Username cannot start with an underscore'
  })
  .refine((username) => !username.endsWith('_'), {
    message: 'Username cannot end with an underscore'
  });

// Phone number validation
const phoneNumberSchema = z.string()
  .regex(/^+?[1-9]d{1,14}$/, 'Invalid phone number format')
  .transform((phone) => {
    // Normalize phone number format
    return phone.replace(/[^0-9+]/g, '');
  });

// URL validation with protocols
const urlSchema = z.string().url().refine((url) => {
  const protocols = ['http:', 'https:', 'ftp:'];
  try {
    const parsedUrl = new URL(url);
    return protocols.includes(parsedUrl.protocol);
  } catch {
    return false;
  }
}, {
  message: 'URL must use http, https, or ftp protocol'
});

// Color validation
const colorHexSchema = z.string()
  .regex(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/, 'Invalid hex color format')
  .transform((hex) => hex.toLowerCase());

const colorRgbSchema = z.string()
  .regex(/^rgb(s*d+s*,s*d+s*,s*d+s*)$/i, 'Invalid RGB format')
  .transform((rgb) => {
    const matches = rgb.match(/d+/g);
    if (!matches || matches.length !== 3) return null;
    return {
      r: parseInt(matches[0]),
      g: parseInt(matches[1]),
      b: parseInt(matches[2])
    };
  });

// Test advanced validation
try {
  passwordSchema.parse('MySecureP@ssw0rd!'); // ✅
  usernameSchema.parse('john_doe123'); // ✅
  phoneNumberSchema.parse('+1-555-123-4567'); // ✅
  urlSchema.parse('https://example.com'); // ✅
  colorHexSchema.parse('#FF5733'); // ✅
  colorRgbSchema.parse('rgb(255, 87, 51)'); // ✅
} catch (error) {
  console.error('Advanced validation error:', error);
}

// 17. Usage Examples

// Form validation function
function validateUserInput(userData: unknown) {
  const userSchema = z.object({
    name: z.string().min(2).max(50),
    email: z.string().email(),
    age: z.number().min(18).max(120),
    website: z.string().url().optional(),
    bio: z.string().max(500).optional()
  });

  const result = userSchema.safeParse(userData);

  if (result.success) {
    return { success: true, data: result.data };
  } else {
    return {
      success: false,
      errors: result.error.issues.map(issue => ({
        field: issue.path.join('.'),
        message: issue.message
      }))
    };
  }
}

// API response validation
function validateApiResponse(response: unknown) {
  const responseSchema = z.object({
    success: z.boolean(),
    data: z.unknown().optional(),
    error: z.string().optional(),
    timestamp: z.string()
  });

  return responseSchema.parse(response);
}

// Environment variable validation
function validateEnvVars(envVars: Record<string, unknown>) {
  const envSchema = z.object({
    NODE_ENV: z.enum(['development', 'production', 'test']),
    PORT: z.string().transform(Number).pipe(z.number().positive()),
    DATABASE_URL: z.string().url(),
    JWT_SECRET: z.string().min(32),
    API_KEY: z.string().min(16),
    ENABLE_LOGGING: z.string().transform(Boolean).pipe(z.boolean()).default(true),
    MAX_CONNECTIONS: z.string().transform(Number).pipe(z.number().positive()).default(10)
  });

  return envSchema.parse(envVars);
}

// Example usage
console.log('\n--- Usage Examples ---');

const userInput = {
  name: 'John Doe',
  email: '[email protected]',
  age: 25,
  website: 'https://johndoe.com',
  bio: 'Software developer'
};

const userValidation = validateUserInput(userInput);
console.log('User validation:', userValidation);

const apiResponse = {
  success: true,
  data: { message: 'Hello World' },
  timestamp: new Date().toISOString()
};

const validatedResponse = validateApiResponse(apiResponse);
console.log('API response validation:', validatedResponse);

const envVars = {
  NODE_ENV: 'development',
  PORT: '3000',
  DATABASE_URL: 'https://localhost:5432/mydb',
  JWT_SECRET: 'my-super-secret-jwt-key-32-chars-long',
  API_KEY: 'my-api-key-16-chars'
};

const validatedEnv = validateEnvVars(envVars);
console.log('Environment validation:', validatedEnv);

export {
  stringSchema,
  numberSchema,
  booleanSchema,
  dateSchema,
  userSchema: z.object({
    name: z.string().min(2).max(50),
    email: z.string().email(),
    age: z.number().min(18).max(120),
    website: z.string().url().optional(),
    bio: z.string().max(500).optional()
  }),
  passwordSchema,
  usernameSchema,
  validateUserInput,
  validateApiResponse,
  validateEnvVars
};
CodetypescriptIntermediate

Zod Objects and Arrays

Complex Zod schemas for objects, arrays, nested structures, and advanced validation patterns

Difficulty

6/10

Estimated time

40 min

Tags

zod, validation, typescript, schemas, objects

Prerequisites

Zod basics, TypeScript, Advanced data structures

typescript
// Zod Objects and Arrays Example

import { z } from 'zod';

// 1. Basic Object Schema
const userSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(2).max(50),
  email: z.string().email(),
  age: z.number().min(13).max(120),
  isActive: z.boolean().default(true),
  createdAt: z.date().default(new Date()),
});

type User = z.infer<typeof userSchema>;

const validUser = {
  id: '550e8400-e29b-41d4-a716-446655440000',
  name: 'John Doe',
  email: '[email protected]',
  age: 30,
  isActive: true,
  createdAt: new Date()
};

console.log(userSchema.parse(validUser)); // ✅

// 2. Partial Object (for updates)
const updateUserSchema = userSchema.partial();

const updateData = {
  name: 'Jane Doe',
  age: 28
};

console.log(updateUserSchema.parse(updateData)); // ✅

// 3. Required Object (no optional/extra properties)
const strictUserSchema = z.object({
  name: z.string(),
  email: z.string().email()
}).strict();

console.log(strictUserSchema.parse({ name: 'John', email: '[email protected]' })); // ✅
// strictUserSchema.parse({ name: 'John', email: '[email protected]', extra: 'value' }); // ❌

// 4. Object with Passthrough (allow extra properties)
const passthroughUserSchema = z.object({
  name: z.string(),
  email: z.string().email()
}).passthrough();

console.log(passthroughUserSchema.parse({
  name: 'John',
  email: '[email protected]',
  role: 'admin',
  department: 'IT'
})); // ✅, preserves extra properties

// 5. Object with Catchall (custom handling for extra properties)
const catchallUserSchema = z.object({
  name: z.string(),
  email: z.string().email()
}).catchall(z.string());

console.log(catchallUserSchema.parse({
  name: 'John',
  email: '[email protected]',
  role: 'admin', // ✅, string value
  score: 100 // ❌, not a string
}));

// 6. Array Schemas
const stringArraySchema = z.array(z.string());
const numberArraySchema = z.array(z.number());
const userArraySchema = z.array(userSchema);

console.log(stringArraySchema.parse(['hello', 'world'])); // ✅
console.log(numberArraySchema.parse([1, 2, 3])); // ✅
console.log(userArraySchema.parse([validUser, validUser])); // ✅

// 7. Array Constraints
const minLengthArray = z.array(z.string()).min(2);
const maxLengthArray = z.array(z.number()).max(5);
const exactLengthArray = z.array(z.string()).length(3);

console.log(minLengthArray.parse(['a', 'b', 'c'])); // ✅
console.log(maxLengthArray.parse([1, 2, 3])); // ✅
console.log(exactLengthArray.parse(['x', 'y', 'z'])); // ✅

// 8. Non-empty Array
const nonEmptyArray = z.array(z.string()).nonempty();
console.log(nonEmptyArray.parse(['hello'])); // ✅
// nonEmptyArray.parse([]); // ❌

// 9. Set-like Array (unique values)
const uniqueArray = z.array(z.string()).refine(
  (arr) => new Set(arr).size === arr.length,
  { message: 'Array must contain unique values' }
);

console.log(uniqueArray.parse(['a', 'b', 'c'])); // ✅
// uniqueArray.parse(['a', 'b', 'a']); // ❌

// 10. Nested Objects
const addressSchema = z.object({
  street: z.string(),
  city: z.string(),
  state: z.string().length(2),
  zipCode: z.string().regex(/^d{5}(-d{4})?$/),
  country: z.string().default('USA'),
  coordinates: z.object({
    lat: z.number().min(-90).max(90),
    lng: z.number().min(-180).max(180)
  }).optional()
});

const userWithAddressSchema = z.object({
  id: z.string().uuid(),
  name: z.string(),
  email: z.string().email(),
  address: addressSchema,
  phoneNumbers: z.array(z.string().regex(/^+?[1-9]d{1,14}$/)).optional(),
  metadata: z.record(z.unknown()).optional()
});

const userWithAddress = {
  id: '550e8400-e29b-41d4-a716-446655440000',
  name: 'John Doe',
  email: '[email protected]',
  address: {
    street: '123 Main St',
    city: 'New York',
    state: 'NY',
    zipCode: '10001',
    coordinates: { lat: 40.7128, lng: -74.0060 }
  },
  phoneNumbers: ['+1-555-123-4567'],
  metadata: {
    lastLogin: new Date().toISOString(),
    preferences: { theme: 'dark' }
  }
};

console.log(userWithAddressSchema.parse(userWithAddress)); // ✅

// 11. Array of Objects
const postSchema = z.object({
  id: z.string().uuid(),
  title: z.string().min(1).max(200),
  content: z.string().max(10000),
  authorId: z.string().uuid(),
  tags: z.array(z.string().min(1).max(20)).max(5),
  published: z.boolean().default(false),
  createdAt: z.date(),
  updatedAt: z.date().optional()
});

const postsSchema = z.array(postSchema);

const posts = [
  {
    id: '550e8400-e29b-41d4-a716-446655440001',
    title: 'Hello World',
    content: 'This is my first post',
    authorId: '550e8400-e29b-41d4-a716-446655440000',
    tags: ['intro', 'hello'],
    published: true,
    createdAt: new Date()
  },
  {
    id: '550e8400-e29b-41d4-a716-446655440002',
    title: 'Second Post',
    content: 'Another interesting post',
    authorId: '550e8400-e29b-41d4-a716-446655440000',
    tags: ['updates', 'announcement'],
    published: false,
    createdAt: new Date()
  }
];

console.log(postsSchema.parse(posts)); // ✅

// 12. Discriminated Unions
const baseEventSchema = z.object({
  id: z.string().uuid(),
  timestamp: z.date(),
  userId: z.string().uuid()
});

const userLoginEventSchema = baseEventSchema.extend({
  type: z.literal('user.login'),
  ipAddress: z.string().ip(),
  userAgent: z.string()
});

const userLogoutEventSchema = baseEventSchema.extend({
  type: z.literal('user.logout'),
  sessionDuration: z.number().positive()
});

const postCreatedEventSchema = baseEventSchema.extend({
  type: z.literal('post.created'),
  postId: z.string().uuid(),
  postTitle: z.string()
});

const eventSchema = z.discriminatedUnion('type', [
  userLoginEventSchema,
  userLogoutEventSchema,
  postCreatedEventSchema
]);

type Event = z.infer<typeof eventSchema>;

// Valid events
const loginEvent = {
  id: '550e8400-e29b-41d4-a716-446655440003',
  timestamp: new Date(),
  userId: '550e8400-e29b-41d4-a716-446655440000',
  type: 'user.login' as const,
  ipAddress: '192.168.1.1',
  userAgent: 'Mozilla/5.0...'
};

const logoutEvent = {
  id: '550e8400-e29b-41d4-a716-446655440004',
  timestamp: new Date(),
  userId: '550e8400-e29b-41d4-a716-446655440000',
  type: 'user.logout' as const,
  sessionDuration: 3600
};

const postEvent = {
  id: '550e8400-e29b-41d4-a716-446655440005',
  timestamp: new Date(),
  userId: '550e8400-e29b-41d4-a716-446655440000',
  type: 'post.created' as const,
  postId: '550e8400-e29b-41d4-a716-446655440001',
  postTitle: 'Hello World'
};

console.log(eventSchema.parse(loginEvent)); // ✅
console.log(eventSchema.parse(logoutEvent)); // ✅
console.log(eventSchema.parse(postEvent)); // ✅

// 13. Record Schema (key-value object)
const configSchema = z.record(z.string(), z.unknown());

const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  retries: 3,
  features: {
    darkMode: true,
    notifications: false
  }
};

console.log(configSchema.parse(config)); // ✅

// More specific record schema
const themeConfigSchema = z.record(z.enum(['primary', 'secondary', 'success', 'danger', 'warning', 'info']), z.string());

const themeConfig = {
  header: 'primary',
  sidebar: 'secondary',
  buttons: 'success',
  alerts: 'danger',
  notifications: 'warning',
  links: 'info'
};

console.log(themeConfigSchema.parse(themeConfig)); // ✅

// 14. Tuple Schema
const coordinateSchema = z.tuple([z.number(), z.number()]);
const rgbColorSchema = z.tuple([z.number().min(0).max(255), z.number().min(0).max(255), z.number().min(0).max(255)]);

console.log(coordinateSchema.parse([10, 20])); // ✅
console.log(rgbColorSchema.parse([255, 128, 0])); // ✅

// 15. Optional Array Elements
const profileSchema = z.object({
  username: z.string(),
  email: z.string().email(),
  socialLinks: z.array(z.object({
    platform: z.string(),
    url: z.string().url()
  })).optional(),
  skills: z.array(z.string()).optional()
});

const profile = {
  username: 'johndoe',
  email: '[email protected]',
  socialLinks: [
    { platform: 'twitter', url: 'https://twitter.com/johndoe' },
    { platform: 'github', url: 'https://github.com/johndoe' }
  ],
  skills: ['TypeScript', 'React', 'Node.js']
};

console.log(profileSchema.parse(profile)); // ✅

// 16. Recursive Schema (self-referencing)
const categorySchema = z.object({
  id: z.string(),
  name: z.string(),
  description: z.string().optional(),
  parentCategory: z.string().optional()
});

const categoryWithChildren = categorySchema.extend({
  subcategories: z.lazy(() => z.array(categoryWithChildren)).optional()
});

// Valid category with nested children
const categoryTree = {
  id: 'cat1',
  name: 'Technology',
  description: 'All things tech',
  subcategories: [
    {
      id: 'cat2',
      name: 'Programming',
      subcategories: [
        {
          id: 'cat3',
          name: 'JavaScript',
          parentCategory: 'cat2'
        },
        {
          id: 'cat4',
          name: 'Python',
          parentCategory: 'cat2'
        }
      ]
    },
    {
      id: 'cat5',
      name: 'Hardware',
      parentCategory: 'cat1'
    }
  ]
};

console.log(categoryWithChildren.parse(categoryTree)); // ✅

// 17. Complex Validation Examples

// Product schema with inventory management
const productSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1).max(100),
  description: z.string().max(1000),
  price: z.number().positive(),
  categories: z.array(z.string().uuid()).min(1),
  variants: z.array(z.object({
    id: z.string().uuid(),
    name: z.string(),
    sku: z.string(),
    price: z.number().positive().optional(),
    inventory: z.object({
      quantity: z.number().min(0),
      lowStockThreshold: z.number().min(0),
      trackInventory: z.boolean()
    }),
    attributes: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])),
    images: z.array(z.object({
      url: z.string().url(),
      alt: z.string().optional(),
      isPrimary: z.boolean().default(false)
    }))
  })).min(1),
  tags: z.array(z.string()).max(10).optional(),
  metadata: z.object({
    weight: z.number().positive().optional(),
    dimensions: z.object({
      length: z.number().positive(),
      width: z.number().positive(),
      height: z.number().positive(),
      unit: z.enum(['cm', 'in', 'mm']).default('cm')
    }).optional(),
    seo: z.object({
      title: z.string().max(60).optional(),
      description: z.string().max(160).optional(),
      keywords: z.array(z.string()).max(10).optional()
    }).optional()
  }).optional()
});

// Order schema with line items
const orderItemSchema = z.object({
  productId: z.string().uuid(),
  variantId: z.string().uuid(),
  quantity: z.number().positive().max(100),
  price: z.number().positive(),
  discounts: z.array(z.object({
    type: z.enum(['percentage', 'fixed']),
    value: z.number().positive(),
    reason: z.string().optional()
  })).optional()
});

const orderSchema = z.object({
  id: z.string().uuid(),
  customerId: z.string().uuid(),
  items: z.array(orderItemSchema).min(1),
  status: z.enum(['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled']),
  shippingAddress: addressSchema,
  billingAddress: addressSchema,
  paymentMethod: z.object({
    type: z.enum(['credit_card', 'debit_card', 'paypal', 'stripe']),
    lastFour: z.string().length(4).regex(/^d+$/),
    brand: z.string().optional()
  }),
  subtotal: z.number().positive(),
  tax: z.number().nonnegative(),
  shipping: z.number().nonnegative(),
  total: z.number().positive(),
  createdAt: z.date(),
  shippedAt: z.date().optional(),
  deliveredAt: z.date().optional()
});

// Validation functions for complex scenarios
function validateProductInventory(product: unknown, requestedQuantity: number) {
  const parsedProduct = productSchema.parse(product);

  for (const variant of parsedProduct.variants) {
    if (variant.inventory.quantity < requestedQuantity) {
      throw new Error(`Insufficient inventory for variant ${variant.name}. Available: ${variant.inventory.quantity}, Requested: ${requestedQuantity}`);
    }

    if (variant.inventory.trackInventory && variant.inventory.quantity <= variant.inventory.lowStockThreshold) {
      console.warn(`Low stock warning for variant ${variant.name}. Current stock: ${variant.inventory.quantity}`);
    }
  }

  return parsedProduct;
}

function validateOrderTotal(order: unknown) {
  const parsedOrder = orderSchema.parse(order);

  const calculatedSubtotal = parsedOrder.items.reduce((sum, item) => {
    const itemTotal = item.price * item.quantity;
    const discountTotal = (item.discounts || []).reduce((discountSum, discount) => {
      if (discount.type === 'percentage') {
        return discountSum + (itemTotal * discount.value / 100);
      } else {
        return discountSum + discount.value;
      }
    }, 0);
    return sum + (itemTotal - discountTotal);
  }, 0);

  if (Math.abs(calculatedSubtotal - parsedOrder.subtotal) > 0.01) {
    throw new Error(`Subtotal mismatch. Calculated: ${calculatedSubtotal}, Provided: ${parsedOrder.subtotal}`);
  }

  const calculatedTotal = calculatedSubtotal + parsedOrder.tax + parsedOrder.shipping;
  if (Math.abs(calculatedTotal - parsedOrder.total) > 0.01) {
    throw new Error(`Total mismatch. Calculated: ${calculatedTotal}, Provided: ${parsedOrder.total}`);
  }

  return parsedOrder;
}

// Test complex validation
try {
  const testProduct = {
    id: '550e8400-e29b-41d4-a716-446655440006',
    name: 'Wireless Headphones',
    description: 'High-quality wireless headphones with noise cancellation',
    price: 99.99,
    categories: ['cat1', 'cat2'],
    variants: [
      {
        id: 'var1',
        name: 'Black',
        sku: 'WH-BLK-001',
        inventory: {
          quantity: 50,
          lowStockThreshold: 10,
          trackInventory: true
        },
        attributes: { color: 'black', wireless: true },
        images: [
          { url: 'https://example.com/headphones-black.jpg', alt: 'Black wireless headphones', isPrimary: true }
        ]
      }
    ]
  };

  validateProductInventory(testProduct, 5); // ✅

  const testOrder = {
    id: 'order1',
    customerId: 'customer1',
    items: [
      {
        productId: 'product1',
        variantId: 'var1',
        quantity: 2,
        price: 99.99
      }
    ],
    status: 'pending' as const,
    shippingAddress: {
      street: '123 Main St',
      city: 'New York',
      state: 'NY',
      zipCode: '10001'
    },
    billingAddress: {
      street: '123 Main St',
      city: 'New York',
      state: 'NY',
      zipCode: '10001'
    },
    paymentMethod: {
      type: 'credit_card' as const,
      lastFour: '1234',
      brand: 'Visa'
    },
    subtotal: 199.98,
    tax: 16.00,
    shipping: 5.00,
    total: 220.98,
    createdAt: new Date()
  };

  validateOrderTotal(testOrder); // ✅
} catch (error) {
  console.error('Complex validation error:', error);
}

export {
  userSchema,
  addressSchema,
  userWithAddressSchema,
  postSchema,
  postsSchema,
  eventSchema,
  productSchema,
  orderItemSchema,
  orderSchema,
  validateProductInventory,
  validateOrderTotal,
  type User,
  type Event
};
CodetypescriptComplex

Zod Advanced Patterns

Advanced Zod patterns including custom validators, error handling, schema composition, middleware, and real-world use cases

Difficulty

9/10

Estimated time

60 min

Tags

zod, validation, patterns, typescript, advanced

Prerequisites

Advanced Zod, TypeScript, Design patterns, Async/await

typescript
// Zod Advanced Patterns and Real-World Examples

import { z, ZodIssue, ZodSchema } from 'zod';

// 1. Custom Validation with Detailed Error Messages

// Enhanced string validation with multiple custom rules
const enhancedStringSchema = z.string()
  .min(3, 'String must be at least 3 characters long')
  .max(100, 'String must be at most 100 characters long')
  .regex(/^[a-zA-Z0-9\s-_]+$/, 'String can only contain letters, numbers, spaces, hyphens, and underscores')
  .refine((val) => val.trim() === val, {
    message: 'String cannot have leading or trailing whitespace'
  })
  .refine((val) => {
    const wordCount = val.trim().split(/\s+/).length;
    return wordCount >= 2;
  }, {
    message: 'String must contain at least 2 words'
  })
  .transform((val) => val.trim());

// Custom ID validator with format checking
const idSchema = z.string()
  .regex(/^[a-zA-Z0-9_-]+$/, 'ID can only contain letters, numbers, hyphens, and underscores')
  .min(3, 'ID must be at least 3 characters long')
  .max(50, 'ID must be at most 50 characters long')
  .refine((val) => /^[a-zA-Z]/.test(val), {
    message: 'ID must start with a letter'
  })
  .refine((val) => !/[-_]{2,}/.test(val), {
    message: 'ID cannot contain consecutive hyphens or underscores'
  });

// 2. Schema Composition and Reuse

// Base field schemas for reuse
const baseFieldSchemas = {
  id: idSchema,
  name: z.string().min(1).max(100),
  description: z.string().max(500).optional(),
  createdAt: z.date(),
  updatedAt: z.date().optional(),
  isActive: z.boolean().default(true)
};

// Timestamp schema with validation
const timestampSchema = z.date()
  .refine((date) => date <= new Date(), {
    message: 'Date cannot be in the future'
  })
  .refine((date) => date >= new Date('2000-01-01'), {
    message: 'Date must be after year 2000'
  });

// 3. Advanced Error Handling

// Custom error formatting
const formatZodError = (error: z.ZodError) => {
  return {
    success: false,
    error: {
      code: error.issues[0]?.code || 'VALIDATION_ERROR',
      message: error.issues[0]?.message || 'Validation failed',
      field: error.issues[0]?.path?.join('.') || 'unknown',
      details: error.issues.map(issue => ({
        field: issue.path?.join('.') || 'unknown',
        code: issue.code,
        message: issue.message,
        received: issue.received,
        expected: issue.expected
      }))
    }
  };
};

// Custom error class for validation
class ValidationError extends Error {
  constructor(
    message: string,
    public readonly code: string,
    public readonly field?: string,
    public readonly details?: ZodIssue[]
  ) {
    super(message);
    this.name = 'ValidationError';
  }
}

// Enhanced safe parse with custom error handling
function safeParseWithCustomError<T>(schema: ZodSchema<T>, data: unknown): T {
  const result = schema.safeParse(data);

  if (!result.success) {
    const firstError = result.error.issues[0];
    throw new ValidationError(
      firstError.message,
      firstError.code,
      firstError.path?.join('.'),
      result.error.issues
    );
  }

  return result.data;
}

// 4. Middleware Pattern for Validation

// Validation middleware type
type ValidationMiddleware<T> = (data: unknown) => T;

// Create validation middleware
function createValidationMiddleware<T>(schema: ZodSchema<T>): ValidationMiddleware<T> {
  return (data: unknown): T => {
    return safeParseWithCustomError(schema, data);
  };
}

// Higher-order function for validation
function withValidation<T>(
  schema: ZodSchema<T>,
  fn: (validatedData: T) => unknown
) {
  const validate = createValidationMiddleware(schema);

  return (data: unknown) => {
    const validatedData = validate(data);
    return fn(validatedData);
  };
}

// 5. Async Validation Patterns

// Async validator for checking uniqueness
async function createUniqueEmailValidator(existingEmails: Set<string>) {
  return async (email: string) => {
    // Simulate database check
    await new Promise(resolve => setTimeout(resolve, 100));

    if (existingEmails.has(email.toLowerCase())) {
      throw new Error('Email already exists');
    }

    return true;
  };
}

// Async schema with custom validation
async function createUserSchema(existingEmails: Set<string> = new Set()) {
  const uniqueEmailValidator = await createUniqueEmailValidator(existingEmails);

  return z.object({
    email: z.string().email().refine(uniqueEmailValidator, {
      message: 'Email must be unique'
    }),
    username: z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]+$/),
    password: z.string()
      .min(8)
      .regex(/[A-Z]/, 'Password must contain uppercase')
      .regex(/[a-z]/, 'Password must contain lowercase')
      .regex(/[0-9]/, 'Password must contain number')
      .regex(/[^A-Za-z0-9]/, 'Password must contain special character')
  });
}

// 6. Conditional Validation

// Conditional object schema based on user type
function createUserProfileSchema(isAdmin: boolean) {
  const baseProfile = z.object({
    firstName: z.string().min(1),
    lastName: z.string().min(1),
    email: z.string().email(),
    bio: z.string().max(500).optional()
  });

  if (isAdmin) {
    return baseProfile.extend({
      adminLevel: z.enum(['junior', 'senior', 'lead']),
      permissions: z.array(z.string()).min(1),
      department: z.string().min(1)
    });
  }

  return baseProfile.extend({
    preferences: z.object({
      theme: z.enum(['light', 'dark']),
      notifications: z.boolean(),
      language: z.string().length(2)
    })
  });
}

// 7. Schema Refactoring with Composition

// Address schema
const addressSchema = z.object({
  street: z.string().min(1),
  city: z.string().min(1),
  state: z.string().length(2),
  zipCode: z.string().regex(/^\d{5}(-\d{4})?$/),
  country: z.string().default('USA'),
  addressType: z.enum(['shipping', 'billing', 'both'])
});

// Contact schema
const contactSchema = z.object({
  phone: z.string().regex(/^\+?[1-9]\d{1,14}$/).optional(),
  email: z.string().email(),
  website: z.string().url().optional(),
  socialMedia: z.record(z.string().url()).optional()
});

// User schema composed from smaller schemas
const createUserSchema = () => z.object({
  ...baseFieldSchemas,
  contact: contactSchema,
  addresses: z.array(addressSchema).min(1),
  role: z.enum(['user', 'admin', 'moderator']).default('user'),
  profile: z.object({
    avatar: z.string().url().optional(),
    timezone: z.string(),
    locale: z.string().default('en-US')
  })
});

// 8. Real-World API Request/Response Validation

// API Request schemas
const PaginationSchema = z.object({
  page: z.coerce.number().positive().default(1),
  limit: z.coerce.number().positive().max(100).default(20),
  sortBy: z.enum(['createdAt', 'updatedAt', 'name']).default('createdAt'),
  sortOrder: z.enum(['asc', 'desc']).default('desc')
});

const FilterSchema = z.object({
  status: z.enum(['active', 'inactive', 'all']).optional(),
  category: z.string().optional(),
  dateFrom: z.string().datetime().optional(),
  dateTo: z.string().datetime().optional(),
  search: z.string().optional()
});

// API Request wrapper
const ApiRequestSchema = z.object({
  pagination: PaginationSchema,
  filters: FilterSchema,
  include: z.array(z.string()).optional()
});

// API Response schemas
const ApiSuccessSchema = <T>(dataSchema: ZodSchema<T>) => z.object({
  success: z.literal(true),
  data: dataSchema,
  pagination: z.object({
    currentPage: z.number(),
    totalPages: z.number(),
    totalItems: z.number(),
    hasNext: z.boolean(),
    hasPrev: z.boolean()
  }).optional(),
  meta: z.record(z.unknown()).optional()
});

const ApiErrorSchema = z.object({
  success: z.literal(false),
  error: z.object({
    code: z.string(),
    message: z.string(),
    details: z.array(z.object({
      field: z.string(),
      code: z.string(),
      message: z.string()
    })).optional()
  }),
  meta: z.record(z.unknown()).optional()
});

// Generic API response schema
const ApiResponseSchema = <T>(dataSchema: ZodSchema<T>) =>
  z.union([ApiSuccessSchema(dataSchema), ApiErrorSchema]);

// 9. Database Model Validation

// UUID validator with fallback
const uuidSchema = z.string().uuid().or(z.string().length(36)).transform((val) => {
  // Handle both UUID and string representation
  return val.length === 36 ? val : val;
});

// Entity status validator
const EntityStatusSchema = z.enum(['active', 'inactive', 'archived', 'pending']).default('active');

// Soft delete mixin
const withSoftDelete = <T extends z.ZodRawShape>(
  schema: T
) => z.object(schema).extend({
  deletedAt: z.date().nullable().default(null),
  deletedBy: uuidSchema.nullable().default(null)
});

// Audit fields mixin
const withAuditFields = <T extends z.ZodRawShape>(
  schema: T
) => z.object(schema).extend({
  createdAt: z.date().default(() => new Date()),
  updatedAt: z.date().default(() => new Date()),
  createdBy: uuidSchema,
  updatedBy: uuidSchema.optional()
});

// 10. Environment Configuration Validation

// Environment type discriminator
const EnvironmentSchema = z.enum(['development', 'staging', 'production', 'test']);

// Database configuration
const DatabaseConfigSchema = z.object({
  url: z.string().url(),
  ssl: z.boolean().default(true),
  maxConnections: z.number().positive().default(10),
  connectionTimeout: z.number().positive().default(30000),
  idleTimeout: z.number().positive().default(300000)
});

// Server configuration
const ServerConfigSchema = z.object({
  port: z.number().positive().default(3000),
  host: z.string().default('localhost'),
  cors: z.object({
    origin: z.union([z.string(), z.array(z.string())]).default('*'),
    credentials: z.boolean().default(false),
    methods: z.array(z.enum(['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'])).default(['GET', 'POST'])
  }).default({}),
  rateLimit: z.object({
    windowMs: z.number().positive().default(900000), // 15 minutes
    maxRequests: z.number().positive().default(100)
  }).optional()
});

// Complete environment configuration
const EnvironmentConfigSchema = z.object({
  nodeEnv: EnvironmentSchema,
  server: ServerConfigSchema,
  database: DatabaseConfigSchema,
  auth: z.object({
    jwtSecret: z.string().min(32),
    jwtExpiresIn: z.string().default('24h'),
    bcryptRounds: z.number().positive().min(10).max(12).default(12)
  }),
  redis: z.object({
    url: z.string().url().optional(),
    host: z.string().default('localhost'),
    port: z.number().positive().default(6379),
    password: z.string().optional(),
    db: z.number().default(0)
  }).optional(),
  features: z.object({
    enableMetrics: z.boolean().default(false),
    enableLogging: z.boolean().default(true),
    enableCache: z.boolean().default(true),
    enableRateLimit: z.boolean().default(true)
  }).default({})
});

// 11. Form Validation Patterns

// Multi-step form schema
const step1Schema = z.object({
  firstName: z.string().min(1),
  lastName: z.string().min(1),
  email: z.string().email(),
  phone: z.string().regex(/^\+?[1-9]\d{1,14}$/)
});

const step2Schema = z.object({
  address: addressSchema,
  preferences: z.object({
    newsletter: z.boolean().default(false),
    marketing: z.boolean().default(false)
  })
});

const step3Schema = z.object({
  paymentMethod: z.enum(['credit_card', 'paypal', 'bank_transfer']),
  terms: z.boolean().refine(val => val === true, {
    message: 'You must accept the terms and conditions'
  })
});

// Multi-step form validator
function validateMultiStepForm(step: number, data: unknown) {
  switch (step) {
    case 1:
      return step1Schema.parse(data);
    case 2:
      return step2Schema.parse(data);
    case 3:
      return step3Schema.parse(data);
    default:
      throw new Error('Invalid step number');
  }
}

// 12. Real-World Usage Examples

// User registration service
class UserService {
  private existingEmails = new Set<string>();
  private existingUsernames = new Set<string>();

  async registerUser(userData: unknown) {
    const userSchema = await this.createUserRegistrationSchema();
    const validatedUser = safeParseWithCustomError(userSchema, userData);

    // Additional business logic
    await this.checkDuplicateEmail(validatedUser.email);
    await this.checkDuplicateUsername(validatedUser.username);

    const user = await this.createUserInDatabase(validatedUser);

    // Update tracking sets
    this.existingEmails.add(user.email.toLowerCase());
    this.existingUsernames.add(user.username.toLowerCase());

    return user;
  }

  private async createUserRegistrationSchema() {
    const uniqueEmailValidator = await this.createUniqueEmailValidator();

    return z.object({
      username: z.string()
        .min(3)
        .max(20)
        .regex(/^[a-zA-Z0-9_]+$/)
        .refine(async (username) => {
          await new Promise(resolve => setTimeout(resolve, 50)); // Simulate async check
          return !this.existingUsernames.has(username.toLowerCase());
        }, {
          message: 'Username already exists'
        }),
      email: z.string().email(),
      password: z.string().min(8),
      confirmPassword: z.string()
    }).refine((data) => data.password === data.confirmPassword, {
      message: 'Passwords do not match',
      path: ['confirmPassword']
    });
  }

  private async createUniqueEmailValidator() {
    return async (email: string) => {
      await new Promise(resolve => setTimeout(resolve, 50));
      return !this.existingEmails.has(email.toLowerCase());
    };
  }

  private async checkDuplicateEmail(email: string) {
    if (this.existingEmails.has(email.toLowerCase())) {
      throw new ValidationError('Email already exists', 'DUPLICATE_EMAIL', 'email');
    }
  }

  private async checkDuplicateUsername(username: string) {
    if (this.existingUsernames.has(username.toLowerCase())) {
      throw new ValidationError('Username already exists', 'DUPLICATE_USERNAME', 'username');
    }
  }

  private async createUserInDatabase(userData: any) {
    // Simulate database insertion
    await new Promise(resolve => setTimeout(resolve, 100));

    return {
      id: Math.random().toString(36).substr(2, 9),
      ...userData,
      createdAt: new Date(),
      updatedAt: new Date()
    };
  }
}

// API request/response handler
class ApiController {
  handleRequest(request: unknown, responseSchema: ZodSchema<any>) {
    try {
      const validatedRequest = safeParseWithCustomError(
        ApiRequestSchema,
        request
      );

      // Process request...
      const data = await this.processRequest(validatedRequest);

      const validatedResponse = ApiSuccessSchema(responseSchema).parse({
        success: true,
        data
      });

      return validatedResponse;

    } catch (error) {
      if (error instanceof ValidationError) {
        return ApiErrorSchema.parse({
          success: false,
          error: {
            code: error.code,
            message: error.message,
            details: error.details?.map(issue => ({
              field: issue.field,
              code: issue.code,
              message: issue.message
            }))
          }
        });
      }

      // Handle other unexpected errors
      return ApiErrorSchema.parse({
        success: false,
        error: {
          code: 'INTERNAL_ERROR',
          message: 'An unexpected error occurred'
        }
      });
    }
  }

  private async processRequest(request: any) {
    // Simulate async processing
    await new Promise(resolve => setTimeout(resolve, 50));
    return { message: 'Request processed successfully' };
  }
}

// 13. Testing with Zod

// Test utilities
function expectValidationSuccess<T>(schema: ZodSchema<T>, data: unknown): T {
  const result = schema.safeParse(data);
  if (!result.success) {
    throw new Error(`Expected validation to succeed, but it failed: ${result.error.message}`);
  }
  return result.data;
}

function expectValidationFailure<T>(schema: ZodSchema<T>, data: unknown, expectedError?: string): void {
  const result = schema.safeParse(data);
  if (result.success) {
    throw new Error('Expected validation to fail, but it succeeded');
  }
  if (expectedError && !result.error.message.includes(expectedError)) {
    throw new Error(`Expected error message to contain "${expectedError}", but got: ${result.error.message}`);
  }
}

// Test examples
function runTests() {
  console.log('Running Zod validation tests...');

  // Test success cases
  const validUser = expectValidationSuccess(userSchema, {
    id: '550e8400-e29b-41d4-a716-446655440000',
    name: 'John Doe',
    email: '[email protected]',
    age: 30
  });
  console.log('✅ Valid user test passed');

  // Test failure cases
  expectValidationFailure(
    userSchema,
    { id: 'invalid-uuid', name: '', email: 'invalid-email', age: -5 },
    'Expected string'
  );
  console.log('✅ Invalid user test passed');

  console.log('All tests completed successfully!');
}

// Execute tests
runTests();

// 14. Schema Documentation Generator

function generateSchemaDocumentation(schema: ZodSchema<any>, name: string): string {
  const description = schema._def.description || name;
  let docs = `# ${name}\n\n${description}\n\n## Schema Definition\n\n`;

  if (schema._def.typeName === 'ZodObject') {
    docs += '| Property | Type | Required | Description |\n';
    docs += '|---------|------|----------|-------------|\n';

    for (const [key, def] of Object.entries(schema._def.shape())) {
      const type = def._def.typeName;
      const required = !def._def.defaultValue;
      const description = def._def.description || '';

      docs += `| ${key} | ${type} | ${required ? 'Yes' : 'No'} | ${description} |\n`;
    }
  }

  return docs;
}

export {
  enhancedStringSchema,
  idSchema,
  formatZodError,
  ValidationError,
  safeParseWithCustomError,
  createValidationMiddleware,
  withValidation,
  ApiRequestSchema,
  ApiResponseSchema,
  EnvironmentConfigSchema,
  validateMultiStepForm,
  UserService,
  ApiController,
  expectValidationSuccess,
  expectValidationFailure,
  generateSchemaDocumentation
};

Tools

Tools frequently paired with this sample

Related

Related sample collections

Tool usage guide

Sample-focused context for search and workflow understanding

Title

Zod Schema Validation

Description

Zod TypeScript-first schema validation examples including primitives, objects, arrays, transforms, custom validators, and error handling

Overview

Zod TypeScript-first schema validation examples including primitives, objects, arrays, transforms, custom validators, and error handling

When to use

  • Use this sample set when you want reference inputs for Zod Schema Validation.
  • Use it to preview output formats and compare related sample variants.

How it works

  1. 1Open a sample entry to inspect the prepared example payload or asset.
  2. 2Compare it with related tools to understand how the workflow connects.

Use cases

  • Zod Basics and Primitives
  • Zod Objects and Arrays
  • Zod Advanced Patterns

FAQ

What is included in Zod Schema Validation?

This page includes curated sample entries, related tools, and neighboring sample collections for Zod Schema Validation.

Home
Tools3197
Samples593
Visualizations461
Viewers103
Hubs229
Tags333
Images, Audio & Video655

Image, audio, and video processing, conversion, and optimization tools

Math, Date & Finance644

Calculators, numerics, date logic, statistics, and finance tools

Design & Color296

Color, layout, graphics, visual styling, and design helper tools

Text & Writing209

Writing, cleanup, formatting, extraction, and text analysis tools

Developer & Web193

Developer utilities, networking, web debugging, and automation helpers

Conversion & Encoding175

Format, file, archive, unit, and encoding conversion tools

UI Screenshot Structure Review and Development Handoff
Piano Sketch Creation, MIDI Review and Listening Demo Handoff
Retro Game Texture Review and Asset Handoff
Screenshot-Based Procedure Guide Review and Handoff
Responsive Page Change Review and Evidence Handoff

© 2026 Elysia Tools. All rights reserved.

DocsPricingAboutTerms of ServicePrivacy PolicyCookiesContact

Development

JSON Schema to Zod Schema Converter

Convert JSON Schema JSON/YAML definitions into ready-to-use Zod schemas with nested objects, arrays, enums, and common validation rules

Validation

JSON Schema Validator

Validate JSON data against a JSON Schema to verify structure and data types

AI Tools

MCP Server Contract Tester — stdio + WebSocket Transports, JSON Schema 2020-12 Tool Validation

End-to-end Model Context Protocol contract testing: JSON-RPC 2.0 initialize handshake and version negotiation over stdio (newline-delimited) and WebSocket (one message per text frame), tools/list inputSchema object-root and draft 2020-12 compilation, resources/list + read, prompts/list + get, ping, -32601 error semantics, sampling/createMessage round-trip, and framing discipline — with an embedded reference server for offline self-verification.

Development

JSON Schema Generator

Infer JSON Schema from sample JSON, optionally merge manual schema edits, and validate data against the active schema

Format Conversion

XLSX Sheet To JSON Schema

Infer JSON Schema from worksheet headers and sample rows with types, enum candidates, and basic constraints

Development

Database Schema Diff

Compare two database schemas and generate migration-oriented change reports

Development

Table Schema Generator

Generate SQL table schema definitions

AI Tools

LLM Tool-Calling JSON Schema Builder

Define an LLM tool once and emit validated function-calling payloads for OpenAI, Anthropic and Gemini.

Rust

Web Error Handling Rust Samples

Web Rust error handling examples including exception catching, logging, and parameter validation

TypeScript

Web Error Handling TypeScript Samples

Web TypeScript error handling examples including exception catching, logging, and parameter validation