https://github.com/thonymg/maybe-zod
TypeScript utility library that combines Zod schema validation with error handling using a Maybe monad pattern for negative space programming.
https://github.com/thonymg/maybe-zod
maybe monad typescript zod
Last synced: 10 months ago
JSON representation
TypeScript utility library that combines Zod schema validation with error handling using a Maybe monad pattern for negative space programming.
- Host: GitHub
- URL: https://github.com/thonymg/maybe-zod
- Owner: thonymg
- License: mit
- Created: 2025-04-01T07:57:07.000Z (about 1 year ago)
- Default Branch: master
- Last Pushed: 2025-04-07T08:15:57.000Z (about 1 year ago)
- Last Synced: 2025-08-09T10:43:07.022Z (11 months ago)
- Topics: maybe, monad, typescript, zod
- Language: TypeScript
- Homepage:
- Size: 32.2 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: license
Awesome Lists containing this project
README
# Maybe-Zod
A lightweight TypeScript utility library that combines Zod schema validation with error handling using a Maybe monad pattern. This library provides a clean and type-safe way to validate data and handle errors without try-catch blocks.
## Features
- Type-safe validation using Zod schemas
- Synchronous and asynchronous validation support
- Clean error handling without try-catch blocks
- Zero dependencies (except for Zod)
- Full TypeScript support with type inference
- Comprehensive test coverage
- Support for complex validation scenarios
- Transformation of validated data
- Detailed error messages
## Installation
```bash
# Using npm
npm install maybe-zod
# Using yarn
yarn add maybe-zod
# Using bun
bun add maybe-zod
```
## Usage
### Basic Example
```typescript
import { z } from "zod";
import { Maybe } from "maybe-zod";
// Define your schema
const userSchema = z.object({
name: z.string().min(2).max(50),
age: z.number().int().positive(),
email: z.string().email(),
});
type User = z.infer;
// Define your Output schema
type UserOutput = User && { displayName: string }
// Define your processing function
const processUser = (user: z.infer) => ({
...user,
displayName: `${user.name} (${user.age})`
});
// Create a validated processor
const validateUser = Maybe(processUser, userSchema);
// Use it with valid data
const [error, result] = validateUser({
name: "Alice",
age: 30,
email: "alice@example.com"
});
// error = null
// result = { name: "Alice", age: 30, email: "alice@example.com", displayName: "Alice (30)" }
// Use it with invalid data
const [error, result] = validateUser({
name: "A",
age: -5,
email: "invalid"
});
// error contains validation messages:
// - "String must contain at least 2 character(s)"
// - "Number must be greater than 0"
// - "Invalid email"
// result = null
```
### Advanced Examples
#### 1. Complex Nested Objects
```typescript
const advancedSchema = z.object({
id: z.string().uuid(),
metadata: z.object({
tags: z.array(z.string()).min(1),
createdAt: z.date()
})
});
type Advanced = z.infer;
// Define your Output schema
type AdvancedOutput = { id: string }
const processData = (data: Advanced) => data.id;
const validate = Maybe(processData, advancedSchema);
const [error, result] = validate({
id: '123e4567-e89b-12d3-a456-426614174000',
metadata: {
tags: ['important', 'urgent'],
createdAt: new Date()
}
});
```
#### 2. Optional Fields and Discriminated Unions
```typescript
// Optional fields
const optionalSchema = z.object({
title: z.string(),
description: z.string().optional(),
tags: z.array(z.string()).optional()
});
// Discriminated unions
const resultSchema = z.discriminatedUnion('type', [
z.object({ type: z.literal('success'), value: z.number() }),
z.object({ type: z.literal('error'), message: z.string() })
]);
type OptionalS = z.infer;
// Define your Output schema
type ResultS = z.infer;
const validateResult = Maybe(
(data) => data.type === 'success' ? data.value : 0,
resultSchema
);
const [error, result] = validateResult({ type: 'success', value: 42 });
// result = 42
```
#### 3. Array Transformations
```typescript
const numberArraySchema = z.array(z.number());
const sum = (numbers: number[]) => numbers.reduce((a, b) => a + b, 0);
const validateSum = Maybe(sum, numberArraySchema);
const [error, result] = validateSum([1, 2, 3, 4, 5]);
// result = 15
```
### Async Validation
```typescript
import { AsyncMaybe } from "maybe-zod";
const validateUserAsync = AsyncMaybe(processUser, userSchema);
// Basic async usage
const [error, result] = await validateUserAsync(
Promise.resolve({
name: "Alice",
age: 30,
email: "alice@example.com"
})
);
// Error handling for rejected promises
try {
const [error, result] = await validateUserAsync(
Promise.reject(new Error('Network error'))
);
// error = 'Unknown error'
// result = null
} catch {
// Handle any unexpected errors
}
```
## API Reference
### `Maybe`
```typescript
Maybe(
fn: (params: T) => U,
schema: z.ZodSchema
) => (data: T) => [string | null, U | null]
```
Creates a validation wrapper for synchronous data processing.
#### Parameters:
- `fn`: A function that processes the validated data
- `schema`: A Zod schema that defines the shape and validation rules for the data
- Returns a function that takes input data and returns a tuple of [error, result]
### `AsyncMaybe`
```typescript
AsyncMaybe(
fn: (params: T) => U,
schema: z.ZodSchema
) => (data: Promise) => Promise<[string | null, U | null]>
```
Creates a validation wrapper for asynchronous data processing.
#### Parameters:
- `fn`: A function that processes the validated data
- `schema`: A Zod schema that defines the shape and validation rules for the data
- Returns a function that takes a Promise of input data and returns a Promise of [error, result]
## Error Handling
The library returns errors in a structured format:
- For validation errors, the error message contains a JSON string of all validation failures
- For async operations, unknown errors are caught and returned as 'Unknown error'
- The result is always null when an error occurs
## Best Practices
1. **Type Safety**
- Always define your schemas with proper types
- Use `z.infer` for type inference
2. **Error Handling**
- Always check the error value before using the result
- Handle both validation errors and unknown errors in async operations
3. **Schema Design**
- Keep schemas modular and reusable
- Use schema composition for complex validations
## Testing
The library includes comprehensive tests. Run them using:
```bash
bun test
```
Test coverage includes:
- Basic validations
- Complex object validations
- Array transformations
- Async operations
- Error cases
- Edge cases
## ❤️ Contributors
This project was initiated and is maintained by [ThonyMg](https://github.com/ThonyMg). I am available for freelance work on Svelte and VueJs projects. Feel free to reach out through my [Linkedin profile](https://www.linkedin.com/company/105997457/) for collaboration opportunities.
## ⚖️ License
This project is licensed under the MIT License. For more details, see the [LICENSE](https://github.com/thonymg/maybe-zod/blob/master/license) file.