홈으로 돌아가기

TypeScript 스키마 유효성 검사용 PropertyDescriptors

유효성 검사 라이브러리가 문자열 경로 대신 타입 안전 오류 선택자를 위해 PropertyDescriptors를 사용. 불변 플루언트 API, 런타임 인트로스펙션 및 확장 지원. 생태계를 위한 Standard Schema v1과 완전 호환.

타입 안전 유효성 검사: 문자열 대신 PropertyDescriptors
Advertisement 728x90

TypeScript에서 스키마 검증을 위한 프로퍼티 디스크립터: 타입 안전 오류 처리

JavaScript 프로젝트에서 복잡한 중첩 객체를 검증하는 일은 개발자들에게 늘 골칫거리입니다. 문자열 경로를 사용해 오류를 추출하는 전통적인 방법은 리팩토링 시 런타임 버그를 유발하죠. 해결책은 바로 프로퍼티 디스크립터입니다. 프로퍼티 디스크립터의 구조화된 트리를 통해 타입 안전한 선택자와 완전한 IDE 자동 완성을 제공합니다.

핵심 아이디어는 각 스키마가 노드 트리를 구성하며, 모든 디스크립터가 자신의 프로퍼티 경로, 연결된 스키마, 부모, 접근 메서드를 알고 있다는 점입니다. 이를 통해 취약한 문자열 대신 람다로 선택자를 컴파일할 수 있습니다.

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('City is required'),
            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);

필드를 이름 변경해도 TypeScript가 컴파일 타임에 잡아줍니다. IDE는 완벽한 자동 완성을 제공하죠.

Google AdInline article slot

불변 플루언트 API와 빌더

모든 스키마 메서드 호출은 새로운 인스턴스를 반환해 변이를 방지합니다. 조합과 재사용이 매우 간편해집니다.

라이브러리는 14가지 빌더 타입을 제공합니다:

  • string() — minLength, maxLength, matches, email, url, uuid
  • number() — min, max, positive, negative, finite, multipleOf
  • boolean() — 기본 검증
  • date() — minDate, maxDate
  • object() — 명명된 프로퍼티
  • array() — 타입화된 요소, 비어있지 않음
  • union() — 판별된 유니온
  • tuple() — 고정 길이
  • record() — 동적 키
  • func() — 함수 타입화
  • any() — hasType 포함
  • nul() — null
  • lazy() — 재귀 스키마
  • extern() — Standard Schema v1 래퍼

기본 SchemaBuilder의 공통 메서드:

Google AdInline article slot
  • .optional() — undefined 허용
  • .required('msg') — 필수 필드
  • .nullable() — null 허용
  • .default(value) — 기본값
  • .catch(value) — 오류 시 대체값
  • .readonly() — Readonly<T>
  • .brand<'T'>() — 브랜디드 타입
  • .describe('text') — JSDoc 보존
  • .addValidator(fn) — 커스텀 로직
  • .addPreprocessor(fn) — 전처리
  • .introspect() — 메타데이터

런타임 스키마 인트로스펙션

.introspect() 메서드는 타입, 제약조건, 플래그, 설명, 확장을 포함한 완전한 스키마 설명을 반환합니다. 런타임에서 모든 도구와 통합에 활용 가능합니다.

const Name = string().minLength(2).maxLength(100).describe('User name').optional();

const info = Name.introspect();
// info.type === 'string'
// info.minLength === 2
// info.description === 'User name'

각 빌더에 대해 완전히 확장된 인트로스펙션을 제공합니다. JSON Schema 변환, 폼 생성, 커스텀 렌더러에 이상적입니다.

타입화된 확장 시스템

확장은 컴포저블하고 인트로스펙션 가능한 코어 추가 기능입니다. HEX 색상과 포트 예시:

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: 'Must be a valid HEX color' }]
                };
            });
        }
    }
});

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

확장은 .introspect().extensions에 나타납니다. 내장 확장에는 email, url, uuid, positive, nonempty 등이 있습니다.

Standard Schema v1 호환성

스키마는 tRPC, TanStack Form, React Hook Form, Hono와 원활히 통합되는 Standard Schema v1을 구현합니다. extern()은 Zod/Valibot을 빌더로 래핑합니다.

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

프로퍼티 디스크립터는 혼합 스키마에서도 타입 안전한 오류 접근을 제공합니다.

주요 요약

  • 타입 안전 선택자: 프로퍼티 디스크립터로 문자열 경로와 런타임 버그 제거.
  • 불변 플루언트 API: 부작용 없이 조합 간편.
  • 런타임 인트로스펙션: 모든 도구를 위한 메타데이터 추출.
  • 확장: 타입화된 컴포저블 코어 추가 기능.
  • Standard Schema v1: 생태계 호환성 보장.

— Editorial Team

Advertisement 728x90

다음 읽기