type-compiler
Version:
A TypeScript compiler plugin for enhanced runtime type checking and analysis with Zod validation
189 lines (165 loc) • 6.47 kB
text/typescript
import { z } from 'zod';
import {
User,
Customer,
AdminUser,
SuperUser,
PhysicalProduct,
DigitalProduct,
RegularProduct,
// @ts-ignore - These schemas are generated by the type-compiler at build time
zUser,
// @ts-ignore - These schemas are generated by the type-compiler at build time
zCustomer,
// @ts-ignore - These schemas are generated by the type-compiler at build time
zAdminUser,
// @ts-ignore - These schemas are generated by the type-compiler at build time
zSuperUser,
// @ts-ignore - These schemas are generated by the type-compiler at build time
zPhysicalProduct,
// @ts-ignore - These schemas are generated by the type-compiler at build time
zDigitalProduct,
// @ts-ignore - These schemas are generated by the type-compiler at build time
zRegularProduct
} from './types';
/**
* Helper function to validate and print the result
*/
function validateAndPrint<T>(schema: z.ZodType<T>, data: any, label: string): T | null {
console.log(`\n--- Validating ${label} ---`);
console.log('Input data:', data);
try {
const validatedData = schema.parse(data);
console.log('✅ Validation passed');
console.log('Validated data:', validatedData);
return validatedData;
} catch (error) {
if (error instanceof z.ZodError) {
console.log('❌ Validation failed');
console.log('Errors:', error.errors.map(err => ({
path: err.path.join('.'),
message: err.message
})));
} else {
console.log('❌ Unexpected error:', error);
}
return null;
}
}
/**
* Main function to demonstrate contextual validators
*/
function main() {
console.log('======================================================');
console.log(' CONTEXTUAL VALIDATORS EXAMPLE');
console.log('======================================================');
console.log('This example demonstrates how validation rules differ');
console.log('for the same field name in different contexts (types)');
console.log('======================================================\n');
// Example 1: Compare User vs Customer email validation
console.log('\n[EXAMPLE 1] Different email validation rules');
// Valid User (company email)
const validUser: User = {
id: '1',
name: 'John Employee',
email: 'john@company.com', // Must end with @company.com
role: 'admin', // Must be admin, user, or guest
status: 'active', // Must be active or inactive
createdAt: new Date()
};
// Invalid User (wrong email domain)
const invalidUser = {
id: '2',
name: 'Jane Employee',
email: 'jane@gmail.com', // Invalid (wrong domain)
role: 'admin',
status: 'active',
createdAt: new Date()
};
// Valid Customer (any email domain)
const validCustomer: Customer = {
id: '3',
name: 'Bob Client',
email: 'bob@gmail.com', // Any valid email works
type: 'individual', // Must be individual or business
status: 'pending', // Can be active, inactive, pending, or suspended
createdAt: new Date()
};
validateAndPrint(zUser, validUser, 'Valid User');
validateAndPrint(zUser, invalidUser, 'Invalid User (wrong email domain)');
validateAndPrint(zCustomer, validCustomer, 'Valid Customer');
// Example 2: Different status values for User vs Customer
console.log('\n[EXAMPLE 2] Different status values');
const userWithInvalidStatus = {
...validUser,
status: 'pending' // Invalid for User (only active/inactive allowed)
};
const customerWithSameStatus = {
...validCustomer,
status: 'pending' // Valid for Customer
};
validateAndPrint(zUser, userWithInvalidStatus, 'User with "pending" status');
validateAndPrint(zCustomer, customerWithSameStatus, 'Customer with "pending" status');
// Example 3: Pattern-based type matching for Products
console.log('\n[EXAMPLE 3] Pattern-based validation for Products');
const validPhysicalProduct: PhysicalProduct = {
id: '4',
name: 'Desk Chair',
description: 'Ergonomic office chair',
price: 199.99, // Must be >= 0.01
inventory: 42, // Must be integer >= 0
weight: 15.5,
dimensions: {
length: 24,
width: 24,
height: 48
},
createdAt: new Date()
};
const invalidPhysicalProduct = {
...validPhysicalProduct,
price: 0, // Invalid (must be >= 0.01)
inventory: -5 // Invalid (must be >= 0)
};
// Regular product doesn't get the stricter price validation
const validRegularProduct: RegularProduct = {
id: '5',
name: 'Generic Item',
price: 0.001, // Only needs to be positive, no minimum
createdAt: new Date()
};
validateAndPrint(zPhysicalProduct, validPhysicalProduct, 'Valid Physical Product');
validateAndPrint(zPhysicalProduct, invalidPhysicalProduct, 'Invalid Physical Product');
validateAndPrint(zRegularProduct, validRegularProduct, 'Valid Regular Product (less strict price validation)');
// Example 4: Pattern matching for Admin/Super users
console.log('\n[EXAMPLE 4] Pattern matching for Admin/Super users');
const validAdminUser: AdminUser = {
id: '6',
name: 'Admin Person',
email: 'admin@company.com',
role: 'admin',
permissions: ['read', 'write', 'delete'], // Must be non-empty array
createdAt: new Date()
};
const invalidAdminUser = {
...validAdminUser,
permissions: [] // Invalid (must have at least one permission)
};
const validSuperUser: SuperUser = {
id: '7',
name: 'Super Person',
email: 'super@company.com',
role: 'admin',
permissions: ['read', 'write', 'delete', 'admin'], // Must be non-empty array
createdAt: new Date()
};
validateAndPrint(zAdminUser, validAdminUser, 'Valid Admin User');
validateAndPrint(zAdminUser, invalidAdminUser, 'Invalid Admin User (empty permissions)');
validateAndPrint(zSuperUser, validSuperUser, 'Valid Super User (same validation rules)');
console.log('\n======================================================');
console.log('Contextual validators enable type-specific validation');
console.log('rules even for fields with the same name.');
console.log('======================================================');
}
// Run the examples
main();