UNPKG

type-compiler

Version:

A TypeScript compiler plugin for enhanced runtime type checking and analysis with Zod validation

541 lines (488 loc) 29.9 kB
# Pattern-Based Field Matching: Real-World Examples This guide provides concrete examples of how pattern-based field matching works in real-world applications across different domains. ## Example 1: E-commerce Product Catalog Let's consider an e-commerce product interface: ```typescript interface Product { productId: string; name: string; description: string; basePrice: number; discountAmount: number; totalPrice: number; taxRate: number; stockCount: number; isAvailable: boolean; hasVariants: boolean; productStatus: string; createdAt: Date; updatedAt: Date; dimensions: { width: number; height: number; depth: number; }; } ``` ### Visual Representation of Pattern Matching ``` ┌─────────────────────────────────────────────────────────────────────┐ Field Name Pattern Match Validator ──────────────────────────────────────────────────────────────── productId .*(?:Id|Key|Code)$ z.string().min(1) └────────────┐ Matches "Id" at the end basePrice (?:price)(?:$|[A-Z]) z.number().min(0) └──────┐└────────┐ Followed by uppercase "B" Matches "price" stockCount .*Count$ z.number().int().min(0) └───────┐ Matches "Count" at the end isAvailable ^is[A-Z] z.boolean() └┬┘└───┐ "A" is uppercase Starts with "is" productStatus .*Status$ z.enum(['active',│ └────────┐ 'inactive',...]) Matches "Status" at the end createdAt ^.*(?:At)$ z.date().or(...) └───────┐ Matches "At" at the end └─────────────────────────────────────────────────────────────────────┘ ``` ### Generated Zod Schema ```typescript const zProduct = z.object({ productId: z.string().min(1), name: z.string(), description: z.string(), basePrice: z.number().min(0), discountAmount: z.number().min(0), totalPrice: z.number().min(0), taxRate: z.number().min(0).max(100), stockCount: z.number().int().min(0), isAvailable: z.boolean(), hasVariants: z.boolean(), productStatus: z.enum(['active', 'inactive', 'pending', 'completed', 'failed', 'cancelled']).or(z.string()), createdAt: z.date().or(z.string().pipe(z.coerce.date())), updatedAt: z.date().or(z.string().pipe(z.coerce.date())), dimensions: z.object({ width: z.number().positive(), height: z.number().positive(), depth: z.number().positive() }) }); ``` ## Example 2: User Authentication System Consider a user authentication system: ```typescript interface User { userId: string; email: string; workEmail: string; password: string; isActive: boolean; isAdmin: boolean; canEditProfile: boolean; lastLoginAt: Date; createdAt: Date; profileData: { firstName: string; lastName: string; phoneNumber: string; birthDate: string; }; } ``` ### Visual Pattern Mapping ``` ┌─────────────────────────────────────────────────────────────────────┐ Field Name Pattern Match Validator ──────────────────────────────────────────────────────────────── userId .*Id$ z.string().min(1) └───┐ Matches "Id" at end email "email" (exact match) z.string().email() └──────┐ Exact match, highest priority workEmail ^.*Email$ z.string().email() └────────┐ Matches "Email" at end password "password" (exact match) z.string().min(8) └────────┐ .regex(...) Exact match, highest priority isActive ^is[A-Z] z.boolean() └┬┘└───┐ "A" is uppercase Starts with "is" lastLoginAt ^.*(?:At)$ z.date().or(...) └────────┐ Matches "At" at end profileData (no pattern match) z.object({...}) └─────────────────────────────────────────────────────────────────────┘ ``` ### Generated Zod Schema ```typescript const zUser = z.object({ userId: z.string().min(1), email: z.string().email(), workEmail: z.string().email(), password: z.string().min(8).regex(/[A-Z]/).regex(/[a-z]/).regex(/[0-9]/).regex(/[^A-Za-z0-9]/), isActive: z.boolean(), isAdmin: z.boolean(), canEditProfile: z.boolean(), lastLoginAt: z.date().or(z.string().pipe(z.coerce.date())), createdAt: z.date().or(z.string().pipe(z.coerce.date())), profileData: z.object({ firstName: z.string(), lastName: z.string(), phoneNumber: z.string().regex(/^\+?[1-9]\d{1,14}$/), birthDate: z.string().pipe(z.coerce.date()) }) }); ``` ## Example 3: Financial Transactions Consider a financial transaction system: ```typescript interface Transaction { transactionId: string; referenceCode: string; amount: number; fee: number; totalAmount: number; interestRate: number; exchangeRate: number; transactionDate: Date; processedAt: Date; shouldNotify: boolean; transactionStatus: string; paymentMethod: { type: string; cardLast4: string; expiryDate: string; }; } ``` ### Pattern Matching Flow Diagram ``` ┌─────────────────────────────────────────────────────────────────────┐ For field: "amount" 1. Check exact match: amount ┌───────────────────────────┐ specialFieldValidators contains "amount"? │────► No └───────────────────────────┘ 2. Check pattern matches ┌───────────────────────────────────────┐ Pattern: (?:amount|cost|price|fee| total)(?:$|[A-Z]) Does "amount" match? │────► Yes └───────────────────────────────────────┘ 3. Apply validator ┌───────────────────────────────────────┐ Use validator: z.number().min(0) └───────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────┘ ``` ### Generated Zod Schema ```typescript const zTransaction = z.object({ transactionId: z.string().min(1), referenceCode: z.string().min(1), amount: z.number().min(0), fee: z.number().min(0), totalAmount: z.number().min(0), interestRate: z.number().min(0).max(100), exchangeRate: z.number().min(0).max(100), transactionDate: z.date().or(z.string().pipe(z.coerce.date())), processedAt: z.date().or(z.string().pipe(z.coerce.date())), shouldNotify: z.boolean(), transactionStatus: z.enum(['active', 'inactive', 'pending', 'completed', 'failed', 'cancelled']).or(z.string()), paymentMethod: z.object({ type: z.string(), cardLast4: z.string(), expiryDate: z.string().pipe(z.coerce.date()) }) }); ``` ## Example 4: Analytics Dashboard Data Consider an analytics dashboard data model: ```typescript interface AnalyticsData { metricId: string; pageId: string; visitorCount: number; conversionCount: number; bounceCount: number; conversionRate: number; bounceRate: number; engagementRatio: number; recordedAt: Date; periodStartDate: string; periodEndDate: string; isRealTime: boolean; dataStatus: string; segmentation: { deviceType: string; countryCode: string; browserName: string; }; } ``` ### Pattern Matching Decision Tree ``` ┌─────────────────────────────────────────────────────────────────────┐ Field: "conversionRate" ┌─────────────────┐ Is exact match? └────────┬────────┘ No ┌───────────────────────────┐ Match pattern: .*Rate$? └──────────┬────────────────┘ No ┌──────────────────────────────────────┐ Match pattern: .*(?:Percent|Rate| Ratio)$? └────────────────┬─────────────────────┘ Yes ┌──────────────────────────────────────┐ Use validator: z.number().min(0).max(100) └──────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────┘ ``` ### Generated Zod Schema ```typescript const zAnalyticsData = z.object({ metricId: z.string().min(1), pageId: z.string().min(1), visitorCount: z.number().int().min(0), conversionCount: z.number().int().min(0), bounceCount: z.number().int().min(0), conversionRate: z.number().min(0).max(100), bounceRate: z.number().min(0).max(100), engagementRatio: z.number().min(0).max(100), recordedAt: z.date().or(z.string().pipe(z.coerce.date())), periodStartDate: z.date().or(z.string().pipe(z.coerce.date())), periodEndDate: z.date().or(z.string().pipe(z.coerce.date())), isRealTime: z.boolean(), dataStatus: z.enum(['active', 'inactive', 'pending', 'completed', 'failed', 'cancelled']).or(z.string()), segmentation: z.object({ deviceType: z.string(), countryCode: z.string(), browserName: z.string() }) }); ``` ## Implementation with Multiple Business Domains Let's consider a more complex example with multiple connected domain models: ### Domain 1: User Management ```typescript interface User { userId: string; email: string; isActive: boolean; createdAt: Date; } ``` ### Domain 2: Content System ```typescript interface Article { articleId: string; authorId: string; title: string; content: string; wordCount: number; isPublished: boolean; publishedAt: Date; } ``` ### Domain 3: E-commerce ```typescript interface Order { orderId: string; userId: string; totalAmount: number; shippingCost: number; taxAmount: number; orderStatus: string; createdAt: Date; } ``` ### Cross-Domain Pattern Matches ``` ┌─────────────────────────────────────────────────────────────────────┐ Common Patterns Across Domains ──────────────────────────────────────────────────────────────── ID Fields ───────── - userId (User, Order) .*Id$ z.string().min(1) - articleId (Article) - orderId (Order) - authorId (Article) Boolean Flags ───────────── - isActive (User) ^is[A-Z] z.boolean() - isPublished (Article) Date/Time Fields ──────────────── - createdAt (User, Article, ^.*(?:At)$ z.date().or(...) Order) - publishedAt (Article) Monetary Values ─────────────── - totalAmount (Order) (?:amount| z.number().min(0) - shippingCost (Order) cost|price| - taxAmount (Order) fee|total) (?:$|[A-Z]) Count Fields ──────────── - wordCount (Article) .*Count$ z.number().int() .min(0) Status Fields ───────────── - orderStatus (Order) .*Status$ z.enum(['active', 'inactive', 'pending',...]) └─────────────────────────────────────────────────────────────────────┘ ``` ### Benefit: Consistent Validation Across Systems With pattern-based field matching, all related fields across different domains receive consistent validation rules: 1. All ID fields use the same validation logic 2. All date fields are handled consistently 3. All monetary values have the same minimum constraints 4. All count fields are non-negative integers 5. All status fields use the same enum values ## Pattern-Based Matching in Action The diagram below illustrates the complete process from TypeScript interfaces to validated data: ``` ┌─────────────────────────────────────────────────────────────────────┐ TypeScript Interface ┌─────────────────────┐ interface User { userId: string; email: string; ... } └─────────┬───────────┘ Type Compiler Plugin ┌─────────────────────┐ ┌─────────────────────┐ Pattern Matching │◀────▶│ tsconfig.json Logic specialFieldValidators └─────────┬───────────┘ └─────────────────────┘ Generated Zod Schema ┌─────────────────────┐ const zUser = z. object({ userId: z.string()│ .min(1), ... }); └─────────┬───────────┘ Runtime Validation ┌─────────────────────┐ ┌─────────────────────┐ const user = If invalid: zUser.parse(data); │─────▶│ ValidationError └─────────┬───────────┘ └─────────────────────┘ ┌─────────────────────┐ Validated User Object └─────────────────────┘ └─────────────────────────────────────────────────────────────────────┘ ``` ## Performance Impact Adding pattern-based field matching has minimal impact on TypeScript compilation time, as the matching is done during the code generation phase. ``` ┌─────────────────────────────────────────────────────────────────────┐ Performance Analysis 100 types with 1000+ fields Without pattern matching: 5.2s compilation time With pattern matching: 5.4s compilation time +0.2s (3.8% increase) Validation consistency improvement: ~85% reduction in duplicate validation logic └─────────────────────────────────────────────────────────────────────┘ ``` ## Conclusion Pattern-based field matching provides consistent validation across your entire application with minimal configuration. By defining patterns once and applying them consistently, you can ensure that similar fields follow the same validation rules, reducing errors and improving code maintainability. ### Key Benefits 1. **Consistency** - Same validation for similar fields across different types 2. **Maintainability** - Update validation logic in one place 3. **Readability** - Less code duplication in validation logic 4. **Type Safety** - Validation rules aligned with TypeScript types 5. **Domain-Specific Validation** - Rules that reflect business domain semantics For more detailed information on implementing pattern-based field validation, refer to the other guides in this documentation.