using-runtime-checks
npx skills add https://github.com/djankies/claude-configs --skill using-runtime-checks
Agent 安装分布
Skill 文档
- Working with API responses or external data
- Parsing JSON from unknown sources
- Handling user input or form data
- Integrating with third-party services
- User mentions validation, Zod, io-ts, runtime checks, or external data
const data: User = await fetch("/api/user").then(r => r.json());
This compiles, but if the API returns { username: string } instead of { name: string }, your code crashes at runtime.
Solution: Runtime validation libraries that:
- Validate data structure at runtime
- Provide TypeScript types automatically
- Generate helpful error messages
Recommended Library: Zod (modern, TypeScript-first, best DX)
Step 1: Define Schema
Create a schema describing the expected shape:
import { z } from "zod";
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
age: z.number().int().positive()
});
Step 2: Extract TypeScript Type
type User = z.infer<typeof UserSchema>;
Step 3: Validate at Runtime
const data = await fetch("/api/user").then(r => r.json());
const result = UserSchema.safeParse(data);
if (result.success) {
const user: User = result.data;
console.log(user.name);
} else {
console.error("Validation failed:", result.error);
}
Step 4: Handle Validation Errors
if (!result.success) {
const issues = result.error.issues.map(issue => ({
path: issue.path.join("."),
message: issue.message
}));
throw new ValidationError("Invalid user data", issues);
}
Setup
import { z } from "zod";
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().min(0).max(150),
role: z.enum(["admin", "user", "guest"]),
createdAt: z.string().datetime()
});
type User = z.infer<typeof UserSchema>;
Validation
async function fetchUser(id: string): Promise<User> {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data: unknown = await response.json();
const result = UserSchema.safeParse(data);
if (!result.success) {
throw new Error(`Invalid user data: ${result.error.message}`);
}
return result.data;
}
Example 2: Form Input Validation
const LoginFormSchema = z.object({
email: z.string().email("Invalid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
rememberMe: z.boolean().optional()
});
type LoginForm = z.infer<typeof LoginFormSchema>;
function validateLoginForm(formData: unknown): LoginForm {
return LoginFormSchema.parse(formData);
}
const form = {
email: "user@example.com",
password: "securepassword123"
};
try {
const validated = validateLoginForm(form);
await login(validated);
} catch (error) {
if (error instanceof z.ZodError) {
error.issues.forEach(issue => {
console.error(`${issue.path.join(".")}: ${issue.message}`);
});
}
}
Example 3: Nested Object Validation
const AddressSchema = z.object({
street: z.string(),
city: z.string(),
state: z.string().length(2),
zipCode: z.string().regex(/^\d{5}(-\d{4})?$/)
});
const UserWithAddressSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
address: AddressSchema,
billingAddress: AddressSchema.optional()
});
type UserWithAddress = z.infer<typeof UserWithAddressSchema>;
Example 4: Array Validation
const TagSchema = z.string().min(1).max(20);
const PostSchema = z.object({
id: z.string(),
title: z.string().min(1).max(200),
content: z.string(),
tags: z.array(TagSchema).min(1).max(10),
metadata: z.record(z.string(), z.unknown())
});
type Post = z.infer<typeof PostSchema>;
async function fetchPosts(): Promise<Post[]> {
const response = await fetch("/api/posts");
const data: unknown = await response.json();
const PostsSchema = z.array(PostSchema);
return PostsSchema.parse(data);
}
Example 5: Advanced Patterns
Union Types: Use discriminated unions for API responses with success/error states.
Transforms: Convert strings to dates or coerce query parameters to numbers.
Refinements: Add custom validation logic for complex business rules (e.g., password strength).
Partial Schemas: Create update schemas from full schemas using .partial().
See references/zod-patterns.md for complete examples of unions, transforms, refinements, and partial schemas.
For complete patterns see references/:
references/zod-patterns.md– Complete Zod API referencereferences/error-handling.md– Validation error handling strategiesreferences/performance.md– Validation performance optimization
For related skills:
- Type Guards: Use the using-type-guards skill for manual type narrowing
- Unknown vs Any: Use the avoiding-any-types skill for why validation is needed
- External Data: Use the validating-external-data skill for specific data source patterns
Cross-Plugin References:
- If constructing Zod schemas for runtime validation, use the validating-schema-basics skill for type-safe Zod v4 schema patterns
- If handling validation errors, use the customizing-errors skill for error formatting and custom messages
- Validate all external data at runtime (APIs, JSON, user input)
- Use
safeParsefor error handling, notparse(unless throwing is desired) - Handle validation errors gracefully with user-friendly messages
- Validate before type assertions
SHOULD:
- Use Zod for new projects (best TypeScript integration)
- Define schemas close to usage
- Reuse schemas for related structures
- Transform data during validation when beneficial
NEVER:
- Trust external data without validation
- Use type assertions (
as Type) on unvalidated data - Ignore validation errors
- Validate in multiple places (validate at boundaries)
- Skip validation for “trusted” sources (trust issues change)
npm install zod
pnpm add zod
yarn add zod
TypeScript configuration:
{
"compilerOptions": {
"strict": true
}
}
Schema Definition: Match expected structure, use appropriate validators, add custom refinements.
Error Handling: Use safeParse, log errors with context, provide user-friendly messages.
Type Safety: Derive types with z.infer, avoid manual assertions after validation.
Performance: Reuse schemas, validate at boundaries only, avoid redundant checks.
Testing: Test valid data, invalid data, and edge cases.
See references/error-handling.md for error handling patterns and references/performance.md for optimization techniques.
io-ts (functional programming style)
import * as t from "io-ts";
const UserCodec = t.type({
id: t.string,
name: t.string,
email: t.string
});
type User = t.TypeOf<typeof UserCodec>;
Yup (common with Formik)
import * as yup from "yup";
const userSchema = yup.object({
name: yup.string().required(),
email: yup.string().email().required()
});
AJV (JSON Schema)
import Ajv from "ajv";
const ajv = new Ajv();
const validate = ajv.compile({
type: "object",
properties: {
name: { type: "string" },
email: { type: "string", format: "email" }
},
required: ["name", "email"]
});
Recommendation: Use Zod for new TypeScript projects. Best DX and type inference.
Validation Middleware: Validate request bodies in Express/framework handlers before processing.
Safe JSON Parse: Combine JSON.parse with schema validation for type-safe parsing.
Configuration Validation: Validate environment variables and config at startup.
See references/zod-patterns.md for complete implementations and additional patterns.