Powrót do strony głównej

PropertyDescriptors do walidacji schematów TypeScript

Biblioteka walidacji używa PropertyDescriptors do type-safe selektorów błędów zamiast ścieżek stringowych. Obsługuje niemutowalny fluent API, introspekcję runtime i rozszerzenia. Pełna kompatybilność ze Standard Schema v1 dla ekosystemu.

Type-safe walidacja: PropertyDescriptors zamiast stringów
Advertisement 728x90

PropertyDescriptors w walidacji schematów: type-safe obsługa błędów

Programiści często napotykają problem walidacji złożonych, zagnieżdżonych obiektów w projektach JavaScript. Standardowe metody oparte na ścieżkach stringowych do wyciągania błędów prowadzą do błędów w runtime podczas refaktoryzacji. Alternatywą są PropertyDescriptors: strukturalne drzewo deskryptorów właściwości, zapewniające type-safe selektory z autouzupełnianiem w IDE.

Kluczowa zasada — każda schemat tworzy drzewo węzłów, gdzie każdy deskryptor zna ścieżkę do właściwości, powiązaną schemę, rodzica i metody dostępu. Dzięki temu selektory kompilowane są przez lambdy zamiast stringów.

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('Miasto jest wymagane'),
            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);

Po zmianie nazwy pola TypeScript zgłosi błąd kompilacji, a IDE zapewni autouzupełnianie.

Google AdInline article slot

Niezmienny fluent API i buildery

Wszystkie wywołania metod na schematach zwracają nowe instancje, eliminując mutacje. Ułatwia to kompozycję i ponowne użycie.

Biblioteka zawiera 14 typów builderów:

  • string() — minLength, maxLength, matches, email, url, uuid
  • number() — min, max, positive, negative, finite, multipleOf
  • boolean() — podstawowa walidacja
  • date() — minDate, maxDate
  • object() — nazwane właściwości
  • array() — typizowane elementy, nonempty
  • union() — dyskryminowane unie
  • tuple() — stałej długości
  • record() — dynamiczne klucze
  • func() — typizacja funkcji
  • any() — z hasType
  • nul() — null
  • lazy() — rekurencyjne schematy
  • extern() — wrapper Standard Schema v1

Wspólne metody bazowego SchemaBuilder:

Google AdInline article slot
  • .optional() — akceptuje undefined
  • .required('msg') — wymagane pole
  • .nullable() — akceptuje null
  • .default(value) — wartość domyślna
  • .catch(value) — przy błędzie
  • .readonly() — Readonly<T>
  • .brand<'T'>() — branded types
  • .describe('text') — zachowanie JSDoc
  • .addValidator(fn) — niestandardowa logika
  • .addPreprocessor(fn) — przedobróbka
  • .introspect() — metadane

Introspekcja schematów w runtime

Metoda .introspect() zwraca pełne opisanie schematu: typ, ograniczenia, flagi, opisy, rozszerzenia. Dane dostępne w runtime dla narzędzi.

const Name = string().minLength(2).maxLength(100).describe('Imię użytkownika').optional();

const info = Name.introspect();
// info.type === 'string'
// info.minLength === 2
// info.description === 'Imię użytkownika'

Introspekcja jest rozszerzana dla każdego buildera. Używana do konwersji JSON Schema, generowania formularzy, niestandardowych rendererów.

System typizowanych rozszerzeń

Rozszerzenia to komponowalne, introspekcjonowalne dodatki do rdzenia. Przykład koloru HEX i portu:

Google AdInline article slot
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: 'Musi być kolor HEX' }]
                };
            });
        }
    }
});

const s = withExtensions(hexColorExt, portExt);
const colorSchema = s.string().hexColor();

Rozszerzenia widoczne w .introspect().extensions. Wbudowane: email, url, uuid, positive, nonempty.

Kompatybilność ze Standard Schema v1

Schematy implementują Standard Schema v1 dla integracji z tRPC, TanStack Form, React Hook Form, Hono. extern() owija Zod/Valibot w buildera.

const UserSchema = object({
    name: string().minLength(2),
    address: extern(zodAddress)
});

PropertyDescriptors zapewniają type-safe dostęp do błędów nawet w mieszanych schematach.

Co najważniejsze

  • Type-safe selektory przez PropertyDescriptors eliminują ścieżki stringowe i błędy runtime.
  • Niezmienność fluent API ułatwia kompozycję bez mutacji.
  • Introspekcja w runtime pozwala wyciągać metadane dla narzędzi.
  • Rozszerzenia — typizowane, komponowalne dodatki do rdzenia.
  • Standard Schema v1 zapewnia kompatybilność z ekosystemem.

— Editorial Team

Advertisement 728x90

Czytaj dalej