PropertyDescriptors při validaci schémat: type-safe přístup k chybám
Vývojáři se často potýkají s validací složitých vnořených objektů v JavaScript projektech. Standardní přístupy s řetězcovými cestami pro získání chyb vedou k runtime chybám při refaktoringu. Alternativa jsou PropertyDescriptors: strukturovaný strom deskriptorů vlastností, který zajišťuje type-safe selektory s autokompletací v IDE.
Klíčový princip – každé schéma vytváří strom uzlů, kde každý deskriptor zná cestu k vlastnosti, přidružené schéma, rodiče a metody přístupu. To umožňuje kompilovat selektory přes lambdy místo řetězců.
import { object, string, number, InferType } from '@cleverbrush/schema';
const OrderSchema = object({
id: string(),
customer: object({
name: string().minLength(2),
email: string().email(),
address: object({
city: string().required('Město je povinné'),
zip: number()
})
}),
total: number().min(0)
});
const result = OrderSchema.validate({
id: '123',
customer: {
name: 'A',
email: 'not-an-email',
address: {
zip: -1
}
},
total: -5
});
const nameErrors = result.getErrorsFor(t => t.customer.name);
const cityErrors = result.getErrorsFor(t => t.customer.address.city);
Při přejmenování pole TypeScript vyhodí chybu kompilace, IDE zajistí autokompletaci.
Imutabilní fluent API a buildery
Všechny volání metod na schématech vracejí nové instance, čímž se vylučují mutace. To usnadňuje kompozici a opětovné použití.
Knihovna obsahuje 14 typů builderů:
string()— minLength, maxLength, matches, email, url, uuidnumber()— min, max, positive, negative, finite, multipleOfboolean()— základní validacedate()— minDate, maxDateobject()— pojmenované vlastnostiarray()— typizované prvky, nonemptyunion()— diskrimminované unietuple()— pevné délkyrecord()— dynamické klíčefunc()— typizace funkcíany()— s hasTypenull()— nulllazy()— rekurzivní schémataextern()— obal Standard Schema v1
Společné metody základního SchemaBuilder:
.optional()— přijímá undefined.required('msg')— povinné pole.nullable()— přijímá null.default(value)— výchozí hodnota.catch(value)— při chybě.readonly()— Readonly<T>.brand<'T'>()— branded types.describe('text')— zachování JSDoc.addValidator(fn)— vlastní logika.addPreprocessor(fn)— předzpracování.introspect()— metadata
Runtime introspekce schémat
Metoda .introspect() vrací úplný popis schématu: typ, omezení, příznaky, popisy, rozšíření. Data jsou dostupná za běhu pro nástroje.
const Name = string().minLength(2).maxLength(100).describe('Jméno uživatele').optional();
const info = Name.introspect();
// info.type === 'string'
// info.minLength === 2
// info.description === 'Jméno uživatele'
Introspekce je rozšířena pro každý builder. Používá se pro konverzi do JSON Schema, generování formulářů, vlastních rendererů.
Systém typizovaných rozšíření
Rozšíření jsou kompozitní, introspektovatelná doplnění jádra. Příklad HEX barvy a portu:
const hexColorExt = defineExtension({
string: {
hexColor(this: StringSchemaBuilder) {
return this.addValidator((v) => {
const valid = /^#[0-9a-f]{6}$/i.test(v as string);
return {
valid,
errors: valid ? [] : [{ message: 'Musí být HEX barva' }]
};
});
}
}
});
const s = withExtensions(hexColorExt, portExt);
const colorSchema = s.string().hexColor();
Rozšíření jsou vidět v .introspect().extensions. Vestavěné: email, url, uuid, positive, nonempty.
Kompatibilita se Standard Schema v1
Schémata implementují Standard Schema v1 pro integraci s tRPC, TanStack Form, React Hook Form, Hono. extern() obaluje Zod/Valibot do builderu.
const UserSchema = object({
name: string().minLength(2),
address: extern(zodAddress)
});
PropertyDescriptors zajišťují type-safe přístup k chybám i ve smíšených schématech.
Co je důležité
- Type-safe selektory přes PropertyDescriptors eliminují řetězcové cesty a runtime chyby.
- Imutabilita fluent API usnadňuje kompozici bez mutací.
- Runtime introspekce umožňuje extrakci metadat pro nástroje.
- Rozšíření — typizovaná, kompozitní doplnění jádra.
- Standard Schema v1 zajišťuje kompatibilitu s ekosystémem.
— Editorial Team
Zatím žádné komentáře.