- JavaScript/TypeScript 기반 스키마 라이브러리들이 공통 인터페이스를 구현하도록 설계된 스펙
- 라이브러리마다 사용자가 정의한 타입 검증 로직을 재사용할 수 있게 하여, 툴들이 별도의 어댑터 없이 서로 호환 가능하게 만드는게 목적
- Zod, Valibot, ArkType 등 주요 라이브러리 제작진이 공동 설계함
주요 인터페이스 (StandardSchemaV1
)
-
~standard
라는 객체 속성을 통해 모든 사양을 구현
-
~standard
내부에 version
, vendor
, validate
, types
등의 필수 프로퍼티 존재
-
validate
함수가 성공 시 value
를, 실패 시 issues
배열을 반환
-
types
프로퍼티로 TypeScript에서 스키마의 입력(input
)과 출력(output
) 타입을 추론할 수 있음
- 모든 업데이트는 메이저 버전이 아닐 경우 호환성을 유지
설계 목표
-
런타임 검증 지원: 스탠다드 방식으로 에러 정보를 표준화해 전달함
-
정적 타입 추론 지원: 타입스크립트 기반 라이브러리들이 추론한 타입 정보를 명시적으로 노출함
-
간결성: 기존 라이브러리 함수에 몇 줄만으로 추가해 구현 가능함
-
API 충돌 회피:
~standard
이름 공간 하나에만 모든 내용을 넣어 기존 API와 충돌하지 않도록 함
-
개발자 경험 유지:
~standard
처럼 틸드(~)로 시작해 자동완성에서 우선순위를 낮춤
어떤 라이브러리가 구현하고 있는가
- 이미 Zod, Valibot, ArkType, Arri Schema, TypeMap 등에서 표준 스키마를 지원 중임
- tRPC, TanStack Form, TanStack Router, Hono Middleware 등도 표준 스키마를 기반으로 유저 스키마를 수용함
자신의 라이브러리에 스펙을 구현하는 방법
-
StandardSchemaV1
인터페이스를 라이브러리에 복사해 ~standard
속성을 추가함
-
validate
함수를 기존 검증 함수에 연결해 성공 시 { value }
, 실패 시 { issues }
를 반환하도록 처리함
- 필요 시 비동기 검증도 가능하지만, 동기 검증을 권장
표준 스키마로 유저 정의 스키마를 받는 방법
- 스키마 라이브러리 없이 직접 사용하려면,
@standard-schema/spec
을 설치하거나 인터페이스를 복사해 사용함
- 예시 함수
standardValidate
처럼 표준 인터페이스를 가진 스키마라면 어떤 라이브러리든 동일한 방식으로 유효성 검증 가능함
- 동기 검증만 허용하려면
validate
반환값이 Promise
인지 확인 후 예외 처리를 하면 됨
FAQ
-
@standard-schema/spec
의존성을 추가해야 하나?: 반드시 의존성으로 추가할 필요는 없고, 복사 후 사용 가능함
-
dev dependency로 추가 불가함: 라이브러리의 퍼블릭 API가 되므로 실제 배포 환경에서도 사용 가능해야 함
-
~standard
앞에 틸데(~)를 사용한 이유: 자동완성에서 다른 속성보다 뒤에 나오도록 의도함
-
Symbol 대신 문자열 키를 사용한 이유: 타입스크립트에서 Symbol 키는 자동완성 정렬이나 타입 추론에 문제가 발생하기 때문