@@ -30,6 +30,11 @@ export function isString(value: unknown): value is string {
3030 return typeof value === "string" ;
3131}
3232
33+ /** Asserts that `value` is a number. */
34+ export function isNumber ( value : unknown ) : value is number {
35+ return typeof value === "number" ;
36+ }
37+
3338/** Asserts that `value` is either a string or undefined. */
3439export function isStringOrUndefined (
3540 value : unknown ,
@@ -55,7 +60,22 @@ export const string = {
5560 required : true ,
5661} as const satisfies Validator < string > ;
5762
58- /** Transforms a validator to be optional. */
63+ /** A validator for number fields in schemas. */
64+ export const number = {
65+ validate : isNumber ,
66+ required : true ,
67+ } as const satisfies Validator < number > ;
68+
69+ /** A validator for object fields in schemas. */
70+ export const object = {
71+ validate : isObject ,
72+ required : true ,
73+ } as const satisfies Validator < UnvalidatedObject < unknown > > ;
74+
75+ /**
76+ * Transforms a validator to be optional, accepting `undefined` or `null` for an
77+ * absent value.
78+ */
5979export function optional < T > ( validator : Validator < T > ) {
6080 return {
6181 validate : ( val : unknown ) => {
@@ -65,6 +85,19 @@ export function optional<T>(validator: Validator<T>) {
6585 } as const satisfies Validator < T | undefined | null > ;
6686}
6787
88+ /**
89+ * Transforms a validator to be optional, accepting `undefined` for an absent
90+ * value but, unlike `optional`, rejecting `null`.
91+ */
92+ export function undefinable < T > ( validator : Validator < T > ) {
93+ return {
94+ validate : ( val : unknown ) : val is T | undefined => {
95+ return val === undefined || validator . validate ( val ) ;
96+ } ,
97+ required : false ,
98+ } as const satisfies Validator < T | undefined > ;
99+ }
100+
68101/** Represents an arbitrary object schema. */
69102export type Schema = Record < string , Validator < any > > ;
70103
0 commit comments