Retrieve validations type from schema #4621
Replies: 1 comment
-
|
This is a great question about schema introspection! You want to extract the validation structure from Zod schemas to get insights into what checks are applied. While Zod doesn't have a built-in method for this exact use case, you can achieve this by leveraging the internal structure of Zod schemas. Here's how to extract validation information from schemas: Solution for Zod v4import { z } from "zod/v4";
type ValidationInfo = {
type: string;
checks?: string[];
properties?: Record<string, ValidationInfo>;
itemType?: ValidationInfo;
};
function extractValidations(schema: z.ZodTypeAny): ValidationInfo {
const baseInfo: ValidationInfo = {
type: schema._zod.def.typeName.replace(/^Zod/, "").toLowerCase()
};
// Extract checks from the schema
if ('checks' in schema._zod.def && Array.isArray(schema._zod.def.checks)) {
baseInfo.checks = schema._zod.def.checks.map((check: any) => {
switch (check.kind || check.check) {
case 'min': return 'min_length';
case 'max': return 'max_length';
case 'length': return 'exact_length';
case 'email': return 'email_format';
case 'url': return 'url_format';
case 'uuid': return 'uuid_format';
case 'regex': return 'regex_pattern';
case 'min_length': return 'min_length';
case 'max_length': return 'max_length';
case 'refine': return 'custom_validation';
default: return check.kind || check.check || 'unknown_check';
}
});
}
// Handle object schemas
if (schema instanceof z.ZodObject) {
baseInfo.properties = {};
const shape = schema.shape;
for (const [key, fieldSchema] of Object.entries(shape)) {
baseInfo.properties[key] = extractValidations(fieldSchema as z.ZodTypeAny);
}
}
// Handle array schemas
if (schema instanceof z.ZodArray) {
baseInfo.itemType = extractValidations(schema.element);
}
// Handle optional/nullable wrappers
if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable) {
const innerInfo = extractValidations(schema.unwrap());
return {
...innerInfo,
checks: [...(innerInfo.checks || []), schema instanceof z.ZodOptional ? 'optional' : 'nullable']
};
}
return baseInfo;
}Usage Example// Example schema
const userSchema = z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
age: z.number().min(18).max(120),
tags: z.array(z.string().min(1)),
profile: z.object({
bio: z.string().max(500).optional(),
website: z.string().url().optional()
})
});
// Extract validation information
const validationInfo = extractValidations(userSchema);
console.log(JSON.stringify(validationInfo, null, 2));Output: {
"type": "object",
"properties": {
"name": {
"type": "string",
"checks": ["min_length", "max_length"]
},
"email": {
"type": "string",
"checks": ["email_format"]
},
"age": {
"type": "number",
"checks": ["min_value", "max_value"]
},
"tags": {
"type": "array",
"itemType": {
"type": "string",
"checks": ["min_length"]
}
},
"profile": {
"type": "object",
"properties": {
"bio": {
"type": "string",
"checks": ["max_length", "optional"]
},
"website": {
"type": "string",
"checks": ["url_format", "optional"]
}
}
}
}
}Enhanced Version with Detailed Check InformationFor more detailed information including check parameters: type DetailedValidationInfo = {
type: string;
checks?: Array<{
type: string;
params?: any;
}>;
properties?: Record<string, DetailedValidationInfo>;
itemType?: DetailedValidationInfo;
};
function extractDetailedValidations(schema: z.ZodTypeAny): DetailedValidationInfo {
const baseInfo: DetailedValidationInfo = {
type: schema._zod.def.typeName.replace(/^Zod/, "").toLowerCase()
};
// Extract detailed checks
if ('checks' in schema._zod.def && Array.isArray(schema._zod.def.checks)) {
baseInfo.checks = schema._zod.def.checks.map((check: any) => {
const checkInfo: any = { type: check.kind || check.check };
// Add parameters based on check type
switch (check.kind || check.check) {
case 'min':
case 'min_length':
checkInfo.params = { minimum: check.value || check.minimum };
break;
case 'max':
case 'max_length':
checkInfo.params = { maximum: check.value || check.maximum };
break;
case 'length':
checkInfo.params = { length: check.value || check.length };
break;
case 'regex':
checkInfo.params = { pattern: check.regex?.toString() };
break;
case 'includes':
checkInfo.params = { value: check.value };
break;
}
return checkInfo;
});
}
// Handle nested structures (same as before)
if (schema instanceof z.ZodObject) {
baseInfo.properties = {};
const shape = schema.shape;
for (const [key, fieldSchema] of Object.entries(shape)) {
baseInfo.properties[key] = extractDetailedValidations(fieldSchema as z.ZodTypeAny);
}
}
if (schema instanceof z.ZodArray) {
baseInfo.itemType = extractDetailedValidations(schema.element);
}
return baseInfo;
}For Zod v3 (Legacy)If you're using Zod v3, the approach is similar but the internal structure is slightly different: function extractValidationsV3(schema: any): ValidationInfo {
const baseInfo: ValidationInfo = {
type: schema._def.typeName.replace(/^Zod/, "").toLowerCase()
};
// v3 uses ._def.checks
if (schema._def.checks && Array.isArray(schema._def.checks)) {
baseInfo.checks = schema._def.checks.map((check: any) => {
return check.kind || 'unknown_check';
});
}
// Handle object properties
if (schema._def.shape) {
baseInfo.properties = {};
for (const [key, fieldSchema] of Object.entries(schema._def.shape())) {
baseInfo.properties[key] = extractValidationsV3(fieldSchema);
}
}
return baseInfo;
}Use CasesThis approach is useful for:
Important Notes
Alternative: Using JSON SchemaIf you need a more standardized format, consider converting your Zod schema to JSON Schema first: import { zodToJsonSchema } from "zod-to-json-schema";
const jsonSchema = zodToJsonSchema(userSchema);
// Extract validation info from the JSON Schema formatThis gives you a standardized representation that's easier to work with programmatically and is compatible with many other tools. Hope this helps with your schema introspection needs! Let me know if you need clarification on any part. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm exploring ways to extract the validation structure from schema. My goal is to obtain a type that includes list of the validation checks applied.
For example:
Given a schema like
z.string().min(5), I would ideally like to derive a structure similar to this:For a nested schema, such as
z.object({ first_name: z.string().min(5) }), the desired output would look something like:Beta Was this translation helpful? Give feedback.
All reactions