💎 Zod 4 is now stable!  Read the announcement.
Zod logo

Metadatos y registros

A menudo es útil asociar un esquema con metadatos adicionales para documentación, generación de código, salidas estructuradas de IA, validación de formularios y otros propósitos.

Registros (Registries)

Los metadatos en Zod se manejan a través de registros. Los registros son colecciones de esquemas, cada uno asociado con algunos metadatos fuertemente tipados. Para crear un registro simple:

import * as z from "zod";
 
const myRegistry = z.registry<{ description: string }>();

Para registrar, buscar y eliminar esquemas de este registro:

const mySchema = z.string();
 
myRegistry.add(mySchema, { description: "A cool schema!"});
myRegistry.has(mySchema); // => true
myRegistry.get(mySchema); // => { description: "A cool schema!" }
myRegistry.remove(mySchema);
myRegistry.clear(); // limpiar registro

TypeScript impone que los metadatos para cada esquema coincidan con el tipo de metadatos del registro.

myRegistry.add(mySchema, { description: "A cool schema!" }); // ✅
myRegistry.add(mySchema, { description: 123 }); // ❌

Manejo especial para id — Los registros de Zod tratan la propiedad id de manera especial. Se lanzará un Error si se registran múltiples esquemas con el mismo valor id. Esto es cierto para todos los registros, incluido el registro global.

.register()

Nota — Este método es especial porque no devuelve un esquema nuevo; en su lugar, devuelve el esquema original. ¡Ningún otro método de Zod hace esto! Eso incluye .meta() y .describe() (documentados abajo) que devuelven una nueva instancia.

Los esquemas proporcionan un método .register() para agregarlo más convenientemente a un registro.

const mySchema = z.string();
 
mySchema.register(myRegistry, { description: "A cool schema!" });
// => mySchema

Esto te permite definir metadatos "en línea" en tus esquemas.

const mySchema = z.object({
  name: z.string().register(myRegistry, { description: "The user's name" }),
  age: z.number().register(myRegistry, { description: "The user's age" }),
})

Si se define un registro sin un tipo de metadatos, puedes usarlo como una "colección" genérica, sin requerir metadatos.

const myRegistry = z.registry();
 
myRegistry.add(z.string());
myRegistry.add(z.number());

Metadatos

z.globalRegistry

Para mayor comodidad, Zod proporciona un registro global (z.globalRegistry) que se puede usar para almacenar metadatos para la generación de JSON Schema u otros propósitos. Acepta los siguientes metadatos:

export interface GlobalMeta {
  id?: string ;
  title?: string ;
  description?: string;
  deprecated?: boolean;
  [k: string]: unknown;
}

Para registrar algunos metadatos en z.globalRegistry para un esquema:

import * as z from "zod";
 
const emailSchema = z.email().register(z.globalRegistry, { 
  id: "email_address",
  title: "Email address",
  description: "Your email address",
  examples: ["[email protected]"]
});

Para aumentar globalmente la interfaz GlobalMeta, usa la fusión de declaraciones. Agrega lo siguiente en cualquier lugar de tu código base. Crear un archivo zod.d.ts en la raíz de tu proyecto es una convención común.

declare module "zod" {
  interface GlobalMeta {
    // añade nuevos campos aquí
    examples?: unknown[];
  }
}
 
// fuerza a TypeScript a considerar el archivo como un módulo
export {}

.meta()

Para un enfoque más conveniente, usa el método .meta() para registrar un esquema en z.globalRegistry.

const emailSchema = z.email().meta({ 
  id: "email_address",
  title: "Email address",
  description: "Please enter a valid email address",
});

Llamar a .meta() sin un argumento recuperará los metadatos para un esquema.

emailSchema.meta();
// => { id: "email_address", title: "Email address", ... }

Los metadatos están asociados con una instancia de esquema específica. Es importante tener esto en cuenta, especialmente porque los métodos de Zod son inmutables: siempre devuelven una nueva instancia.

const A = z.string().meta({ description: "A cool string" });
A.meta(); // => { description: "A cool string" }
 
const B = A.refine(_ => true);
B.meta(); // => undefined

.describe()

El método .describe() todavía existe por compatibilidad con Zod 3, pero .meta() es ahora el enfoque recomendado.

El método .describe() es una abreviatura para registrar un esquema en z.globalRegistry con solo un campo description.

const emailSchema = z.email();
emailSchema.describe("An email address");
 
// equivalente a
emailSchema.meta({ description: "An email address" });

Registros personalizados

Ya has visto un ejemplo simple de un registro personalizado:

import * as z from "zod";
 
const myRegistry = z.registry<{ description: string };>();

Veamos algunos patrones más avanzados.

Referenciar tipos inferidos

A menudo es valioso que el tipo de metadatos haga referencia al tipo inferido de un esquema. Por ejemplo, es posible que desees que un campo examples contenga ejemplos de la salida del esquema.

import * as z from "zod";
 
type MyMeta = { examples: z.$output[] };
const myRegistry = z.registry<MyMeta>();
 
myRegistry.add(z.string(), { examples: ["hello", "world"] });
myRegistry.add(z.number(), { examples: [1, 2, 3] });

El símbolo especial z.$output es una referencia al tipo de salida inferido del esquema (z.infer<typeof schema>). De manera similar, puedes usar z.$input para referenciar el tipo de entrada.

Restringir tipos de esquema

Pasa un segundo genérico a z.registry() para restringir los tipos de esquema que se pueden agregar a un registro. Este registro solo acepta esquemas de cadena.

import * as z from "zod";
 
const myRegistry = z.registry<{ description: string }, z.ZodString>();
 
myRegistry.add(z.string(), { description: "A number" }); // ✅
myRegistry.add(z.number(), { description: "A number" }); // ❌ 
//             ^ 'ZodNumber' is not assignable to parameter of type 'ZodString' 

On this page