Added AI skills
This commit is contained in:
143
.agents/skills/zod/references/refine-catch.md
Normal file
143
.agents/skills/zod/references/refine-catch.md
Normal file
@@ -0,0 +1,143 @@
|
||||
---
|
||||
title: Use catch() for Fault-Tolerant Parsing
|
||||
impact: MEDIUM
|
||||
impactDescription: parse() fails on first invalid field; catch() provides fallback values, enabling partial success with degraded data
|
||||
tags: refine, catch, fallback, resilience
|
||||
---
|
||||
|
||||
## Use catch() for Fault-Tolerant Parsing
|
||||
|
||||
When parsing data that might have some invalid fields but you want to accept what's valid, use `.catch()` to provide fallback values instead of failing entirely. This enables graceful degradation for partially corrupted data.
|
||||
|
||||
**Incorrect (all-or-nothing parsing):**
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod'
|
||||
|
||||
const userPrefsSchema = z.object({
|
||||
theme: z.enum(['light', 'dark']),
|
||||
fontSize: z.number().min(8).max(32),
|
||||
language: z.string(),
|
||||
notifications: z.boolean(),
|
||||
})
|
||||
|
||||
// Corrupted localStorage data
|
||||
const stored = {
|
||||
theme: 'invalid-theme', // Bad
|
||||
fontSize: 200, // Bad
|
||||
language: 'en', // Good
|
||||
notifications: 'yes', // Bad - should be boolean
|
||||
}
|
||||
|
||||
userPrefsSchema.parse(stored)
|
||||
// ZodError: Invalid enum value at "theme"
|
||||
// User loses ALL their preferences because one field is bad
|
||||
```
|
||||
|
||||
**Correct (fault-tolerant with catch):**
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod'
|
||||
|
||||
const userPrefsSchema = z.object({
|
||||
theme: z.enum(['light', 'dark']).catch('light'),
|
||||
fontSize: z.number().min(8).max(32).catch(16),
|
||||
language: z.string().catch('en'),
|
||||
notifications: z.boolean().catch(true),
|
||||
})
|
||||
|
||||
// Corrupted data
|
||||
const stored = {
|
||||
theme: 'invalid-theme',
|
||||
fontSize: 200,
|
||||
language: 'en',
|
||||
notifications: 'yes',
|
||||
}
|
||||
|
||||
const prefs = userPrefsSchema.parse(stored)
|
||||
// {
|
||||
// theme: 'light', // Fallback used
|
||||
// fontSize: 16, // Fallback used
|
||||
// language: 'en', // Original value preserved
|
||||
// notifications: true // Fallback used
|
||||
// }
|
||||
// User gets mostly working preferences instead of error
|
||||
```
|
||||
|
||||
**Catch with factory function:**
|
||||
|
||||
```typescript
|
||||
// Factory function receives the caught error
|
||||
const schema = z.object({
|
||||
data: z.array(z.number()).catch((ctx) => {
|
||||
console.warn('Invalid data array:', ctx.error)
|
||||
return [] // Return empty array as fallback
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
**Use case: API response resilience:**
|
||||
|
||||
```typescript
|
||||
const productSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
price: z.number().positive(),
|
||||
// Legacy field that might be missing or wrong format
|
||||
legacyCode: z.string().catch('UNKNOWN'),
|
||||
// External data that might be malformed
|
||||
metadata: z.record(z.string()).catch({}),
|
||||
})
|
||||
|
||||
// API returns partial data
|
||||
const apiResponse = {
|
||||
id: 'prod-123',
|
||||
name: 'Widget',
|
||||
price: 29.99,
|
||||
legacyCode: null, // Bad - should be string
|
||||
metadata: 'invalid', // Bad - should be object
|
||||
}
|
||||
|
||||
const product = productSchema.parse(apiResponse)
|
||||
// Works! Returns product with fallbacks for bad fields
|
||||
```
|
||||
|
||||
**Difference between catch() and default():**
|
||||
|
||||
```typescript
|
||||
// .default() - only fills in undefined
|
||||
z.string().default('fallback')
|
||||
// undefined -> 'fallback'
|
||||
// null -> ZodError
|
||||
// '' -> '' (empty string is valid)
|
||||
|
||||
// .catch() - fallback for ANY parse failure
|
||||
z.string().catch('fallback')
|
||||
// undefined -> 'fallback'
|
||||
// null -> 'fallback'
|
||||
// 123 -> 'fallback'
|
||||
// Even valid strings pass through unchanged
|
||||
```
|
||||
|
||||
**Combining catch with validation:**
|
||||
|
||||
```typescript
|
||||
// Catch only specific validation failures
|
||||
const schema = z.string()
|
||||
.email()
|
||||
.catch('invalid@example.com') // Fallback if not valid email
|
||||
|
||||
// Chain for complex defaults
|
||||
const ageSchema = z.coerce.number()
|
||||
.int()
|
||||
.min(0)
|
||||
.max(120)
|
||||
.catch(0) // Invalid ages become 0
|
||||
```
|
||||
|
||||
**When NOT to use this pattern:**
|
||||
- When invalid data should cause errors (strict validation)
|
||||
- When you need to know which fields failed (use safeParse)
|
||||
- Critical fields that must be valid
|
||||
|
||||
Reference: [Zod API - catch](https://zod.dev/api#catch)
|
||||
Reference in New Issue
Block a user