typescript - ¿Cómo iterar sobre propiedades y obtener los tipos en Zod?
Supongamos que tienes un sistema básico como este en Zod:
import { z } from 'zod'
const Post = z.object({
title: z.string(),
})
const User = z.object({
name: z.string(),
email: z.string().optional(),
posts: z.array(Post),
loginCount: z.number().min(1)
})
¿Cómo se itera a través de las propiedades e inspeccionan las opciones en las propiedades?
Veo que hay una propiedad .shape, pero ¿cómo se hace esto:
for (const name in shape) {
const prop = shape[name]
if (prop.min != null) {
console.log(`Has min ${prop.min}`)
}
if (prop.max != null) {
console.log(`Has max ${prop.max}`);
}
if (prop.optional === true) {
console.log(`Is optional`);
}
if (prop.type) {
if (prop.type is array) {
prop.type.forEach(item => {
console.log(`Has array item type ${item.name}`)
})
} else if (prop.type is union) {
// ... show union type names
} else {
// show basic type name
}
}
}
Necesito usar esta definición para, por ejemplo:
- Obtener las claves de cada esquema
- Obtén el tipo de propiedad permitido(s) para una propiedad en un esquema (para que pueda saber en qué tabla de base de datos insertar, por ejemplo)
- Hacer documentación
- Cosas así.
No veo ninguna documentación para cosas como esta y no quiero terminar reinventando la rueda haciendo mi propia biblioteca para manejar tipos e inspección de tipos.
Respuesta #1
Zod realmente no está hecho para ser usado así, pero dependiendo de la complejidad de tus esquemas, puedes avanzar bastante mirando el código fuente: https://github.com/colinhacks/zod/blob/master/src/types.ts
Por ejemplo, puedes ver que los distintos tipos son clases, y por ejemplo que el tipo número tiene los getters minValue y maxValue. Entonces, para obtener esos valores, puedes hacer:
if (s instanceof ZodNumber)
console.log(s.minValue, s.maxValue)
El shape que mencionas es un getter en el tipo ZodObject, lo que significa que puedes hacer:
if (s instanceof ZodObject)
for (const field of schema.shape)
// look at each field
También descubrirás que los esquemas opcionales y nulos son las clases ZodOptional y ZodNullable, y que ambas tienen un método unwrap() para mirar los valores internos, lo que significa que podrías hacer algo como esto:
let required = true;
while (s instanceof ZodOptional || s instanceof ZodNullable) {
required = false;
s = s.unwrap();
}
Si haces refinamientos o transformaciones, estos se envolverán en la clase ZodEffects, y allí verás que hay un método innerType() para acceder al tipo interno allí.
Básicamente, solo necesitas recorrer las cosas de manera recursiva, mirar cada cosa, observar de qué tipo es y tratarla según tu necesidad.
