UNPKG

21 kBTypeScriptView Raw
1/**
2 * A `StructFailure` represents a single specific failure in validation.
3 */
4type Failure = {
5 value: any;
6 key: any;
7 type: string;
8 refinement: string | undefined;
9 message: string;
10 branch: Array<any>;
11 path: Array<any>;
12};
13/**
14 * `StructError` objects are thrown (or returned) when validation fails.
15 *
16 * Validation logic is design to exit early for maximum performance. The error
17 * represents the first error encountered during validation. For more detail,
18 * the `error.failures` property is a generator function that can be run to
19 * continue validation and receive all the failures in the data.
20 */
21declare class StructError extends TypeError {
22 value: any;
23 key: any;
24 type: string;
25 refinement: string | undefined;
26 path: Array<any>;
27 branch: Array<any>;
28 failures: () => Array<Failure>;
29 [x: string]: any;
30 constructor(failure: Failure, failures: () => Generator<Failure>);
31}
32/**
33 * Convert a union of type to an intersection.
34 */
35type UnionToIntersection<U> = (U extends any ? (arg: U) => any : never) extends (arg: infer I) => void ? I : never;
36/**
37 * Assign properties from one type to another, overwriting existing.
38 */
39type Assign<T, U> = Simplify<U & Omit<T, keyof U>>;
40/**
41 * A schema for enum structs.
42 */
43type EnumSchema<T extends string | number | undefined> = {
44 [K in NonNullable<T>]: K;
45};
46/**
47 * Check if a type is a match for another whilst treating overlapping
48 * unions as a match.
49 */
50type IsMatch<T, G> = T extends G ? (G extends T ? T : never) : never;
51/**
52 * Check if a type is an exact match.
53 */
54type IsExactMatch<T, U> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? T : never;
55/**
56 * Check if a type is a record type.
57 */
58type IsRecord<T> = T extends object ? string extends keyof T ? T : never : never;
59/**
60 * Check if a type is a tuple.
61 */
62type IsTuple<T> = T extends [
63 any
64] ? T : T extends [
65 any,
66 any
67] ? T : T extends [
68 any,
69 any,
70 any
71] ? T : T extends [
72 any,
73 any,
74 any,
75 any
76] ? T : T extends [
77 any,
78 any,
79 any,
80 any,
81 any
82] ? T : never;
83/**
84 * Check if a type is a union.
85 */
86type IsUnion<T, U extends T = T> = (T extends any ? (U extends T ? false : true) : false) extends false ? never : T;
87/**
88 * A schema for object structs.
89 */
90type ObjectSchema = Record<string, Struct<any, any>>;
91/**
92 * Infer a type from an object struct schema.
93 */
94type ObjectType<S extends ObjectSchema> = Simplify<Optionalize<{
95 [K in keyof S]: Infer<S[K]>;
96}>>;
97/**
98 * Omit properties from a type that extend from a specific type.
99 */
100type OmitBy<T, V> = Omit<T, {
101 [K in keyof T]: V extends Extract<T[K], V> ? K : never;
102}[keyof T]>;
103/**
104 * Normalize properties of a type that allow `undefined` to make them optional.
105 */
106type Optionalize<S extends object> = OmitBy<S, undefined> & Partial<PickBy<S, undefined>>;
107/**
108 * Transform an object schema type to represent a partial.
109 */
110type PartialObjectSchema<S extends ObjectSchema> = {
111 [K in keyof S]: Struct<Infer<S[K]> | undefined>;
112};
113/**
114 * Pick properties from a type that extend from a specific type.
115 */
116type PickBy<T, V> = Pick<T, {
117 [K in keyof T]: V extends Extract<T[K], V> ? K : never;
118}[keyof T]>;
119/**
120 * Simplifies a type definition to its most basic representation.
121 */
122type Simplify<T> = T extends any[] | Date ? T : {
123 [K in keyof T]: T[K];
124} & {};
125/**
126 * A schema for any type of struct.
127 */
128type StructSchema<T> = [
129 T
130] extends [
131 string | undefined
132] ? [
133 T
134] extends [
135 IsMatch<T, string | undefined>
136] ? null : [
137 T
138] extends [
139 IsUnion<T>
140] ? EnumSchema<T> : T : [
141 T
142] extends [
143 number | undefined
144] ? [
145 T
146] extends [
147 IsMatch<T, number | undefined>
148] ? null : [
149 T
150] extends [
151 IsUnion<T>
152] ? EnumSchema<T> : T : [
153 T
154] extends [
155 boolean
156] ? [
157 T
158] extends [
159 IsExactMatch<T, boolean>
160] ? null : T : T extends bigint | symbol | undefined | null | Function | Date | Error | RegExp | Map<any, any> | WeakMap<any, any> | Set<any> | WeakSet<any> | Promise<any> ? null : T extends Array<infer E> ? T extends IsTuple<T> ? null : Struct<E> : T extends object ? T extends IsRecord<T> ? null : {
161 [K in keyof T]: Describe<T[K]>;
162} : null;
163/**
164 * Shorthand type for matching any `Struct`.
165 */
166type AnyStruct = Struct<any, any>;
167/**
168 * Infer a tuple of types from a tuple of `Struct`s.
169 *
170 * This is used to recursively retrieve the type from `union` `intersection` and
171 * `tuple` structs.
172 */
173type InferStructTuple<Tuple extends AnyStruct[], Length extends number = Tuple["length"]> = Length extends Length ? number extends Length ? Tuple : _InferTuple<Tuple, Length, [
174]> : never;
175type _InferTuple<Tuple extends AnyStruct[], Length extends number, Accumulated extends unknown[], Index extends number = Accumulated["length"]> = Index extends Length ? Accumulated : _InferTuple<Tuple, Length, [
176 ...Accumulated,
177 Infer<Tuple[Index]>
178]>;
179/**
180 * `Struct` objects encapsulate the validation logic for a specific type of
181 * values. Once constructed, you use the `assert`, `is` or `validate` helpers to
182 * validate unknown input data against the struct.
183 */
184declare class Struct<T = unknown, S = unknown> {
185 readonly TYPE: T;
186 type: string;
187 schema: S;
188 coercer: (value: unknown, context: Context) => unknown;
189 validator: (value: unknown, context: Context) => Iterable<Failure>;
190 refiner: (value: T, context: Context) => Iterable<Failure>;
191 entries: (value: unknown, context: Context) => Iterable<[
192 string | number,
193 unknown,
194 Struct<any> | Struct<never>
195 ]>;
196 constructor(props: {
197 type: string;
198 schema: S;
199 coercer?: Coercer;
200 validator?: Validator;
201 refiner?: Refiner<T>;
202 entries?: Struct<T, S>["entries"];
203 });
204 /**
205 * Assert that a value passes the struct's validation, throwing if it doesn't.
206 */
207 assert(value: unknown): asserts value is T;
208 /**
209 * Create a value with the struct's coercion logic, then validate it.
210 */
211 create(value: unknown): T;
212 /**
213 * Check if a value passes the struct's validation.
214 */
215 is(value: unknown): value is T;
216 /**
217 * Mask a value, coercing and validating it, but returning only the subset of
218 * properties defined by the struct's schema.
219 */
220 mask(value: unknown): T;
221 /**
222 * Validate a value with the struct's validation logic, returning a tuple
223 * representing the result.
224 *
225 * You may optionally pass `true` for the `withCoercion` argument to coerce
226 * the value before attempting to validate it. If you do, the result will
227 * contain the coerced result when successful.
228 */
229 validate(value: unknown, options?: {
230 coerce?: boolean;
231 }): [
232 StructError,
233 undefined
234 ] | [
235 undefined,
236 T
237 ];
238}
239/**
240 * Assert that a value passes a struct, throwing if it doesn't.
241 */
242declare function assert<T, S>(value: unknown, struct: Struct<T, S>): asserts value is T;
243/**
244 * Create a value with the coercion logic of struct and validate it.
245 */
246declare function create<T, S>(value: unknown, struct: Struct<T, S>): T;
247/**
248 * Mask a value, returning only the subset of properties defined by a struct.
249 */
250declare function mask<T, S>(value: unknown, struct: Struct<T, S>): T;
251/**
252 * Check if a value passes a struct.
253 */
254declare function is<T, S>(value: unknown, struct: Struct<T, S>): value is T;
255/**
256 * Validate a value against a struct, returning an error if invalid, or the
257 * value (with potential coercion) if valid.
258 */
259declare function validate<T, S>(value: unknown, struct: Struct<T, S>, options?: {
260 coerce?: boolean;
261 mask?: boolean;
262}): [
263 StructError,
264 undefined
265] | [
266 undefined,
267 T
268];
269/**
270 * A `Context` contains information about the current location of the
271 * validation inside the initial input value.
272 */
273type Context = {
274 branch: Array<any>;
275 path: Array<any>;
276};
277/**
278 * A type utility to extract the type from a `Struct` class.
279 */
280type Infer<T extends Struct<any, any>> = T["TYPE"];
281/**
282 * A type utility to describe that a struct represents a TypeScript type.
283 */
284type Describe<T> = Struct<T, StructSchema<T>>;
285/**
286 * A `Result` is returned from validation functions.
287 */
288type Result = boolean | string | Partial<Failure> | Iterable<boolean | string | Partial<Failure>>;
289/**
290 * A `Coercer` takes an unknown value and optionally coerces it.
291 */
292type Coercer<T = unknown> = (value: T, context: Context) => unknown;
293/**
294 * A `Validator` takes an unknown value and validates it.
295 */
296type Validator = (value: unknown, context: Context) => Result;
297/**
298 * A `Refiner` takes a value of a known type and validates it against a further
299 * constraint.
300 */
301type Refiner<T> = (value: T, context: Context) => Result;
302/**
303 * Augment a `Struct` to add an additional coercion step to its input.
304 *
305 * This allows you to transform input data before validating it, to increase the
306 * likelihood that it passes validation—for example for default values, parsing
307 * different formats, etc.
308 *
309 * Note: You must use `create(value, Struct)` on the value to have the coercion
310 * take effect! Using simply `assert()` or `is()` will not use coercion.
311 */
312declare function coerce<T, S, C>(struct: Struct<T, S>, condition: Struct<C, any>, coercer: Coercer<C>): Struct<T, S>;
313/**
314 * Augment a struct to replace `undefined` values with a default.
315 *
316 * Note: You must use `create(value, Struct)` on the value to have the coercion
317 * take effect! Using simply `assert()` or `is()` will not use coercion.
318 */
319declare function defaulted<T, S>(struct: Struct<T, S>, fallback: any, options?: {
320 strict?: boolean;
321}): Struct<T, S>;
322/**
323 * Augment a struct to trim string inputs.
324 *
325 * Note: You must use `create(value, Struct)` on the value to have the coercion
326 * take effect! Using simply `assert()` or `is()` will not use coercion.
327 */
328declare function trimmed<T, S>(struct: Struct<T, S>): Struct<T, S>;
329/**
330 * Ensure that a string, array, map, or set is empty.
331 */
332declare function empty<T extends string | any[] | Map<any, any> | Set<any>, S extends any>(struct: Struct<T, S>): Struct<T, S>;
333/**
334 * Ensure that a number or date is below a threshold.
335 */
336declare function max<T extends number | Date, S extends any>(struct: Struct<T, S>, threshold: T, options?: {
337 exclusive?: boolean;
338}): Struct<T, S>;
339/**
340 * Ensure that a number or date is above a threshold.
341 */
342declare function min<T extends number | Date, S extends any>(struct: Struct<T, S>, threshold: T, options?: {
343 exclusive?: boolean;
344}): Struct<T, S>;
345/**
346 * Ensure that a string, array, map or set is not empty.
347 */
348declare function nonempty<T extends string | any[] | Map<any, any> | Set<any>, S extends any>(struct: Struct<T, S>): Struct<T, S>;
349/**
350 * Ensure that a string matches a regular expression.
351 */
352declare function pattern<T extends string, S extends any>(struct: Struct<T, S>, regexp: RegExp): Struct<T, S>;
353/**
354 * Ensure that a string, array, number, date, map, or set has a size (or length, or time) between `min` and `max`.
355 */
356declare function size<T extends string | number | Date | any[] | Map<any, any> | Set<any>, S extends any>(struct: Struct<T, S>, min: number, max?: number): Struct<T, S>;
357/**
358 * Augment a `Struct` to add an additional refinement to the validation.
359 *
360 * The refiner function is guaranteed to receive a value of the struct's type,
361 * because the struct's existing validation will already have passed. This
362 * allows you to layer additional validation on top of existing structs.
363 */
364declare function refine<T, S>(struct: Struct<T, S>, name: string, refiner: Refiner<T>): Struct<T, S>;
365/**
366 * Ensure that any value passes validation.
367 */
368declare function any(): Struct<any, null>;
369/**
370 * Ensure that a value is an array and that its elements are of a specific type.
371 *
372 * Note: If you omit the element struct, the arrays elements will not be
373 * iterated at all. This can be helpful for cases where performance is critical,
374 * and it is preferred to using `array(any())`.
375 */
376declare function array<T extends Struct<any>>(Element: T): Struct<Infer<T>[], T>;
377declare function array(): Struct<unknown[], undefined>;
378/**
379 * Ensure that a value is a bigint.
380 */
381declare function bigint(): Struct<bigint, null>;
382/**
383 * Ensure that a value is a boolean.
384 */
385declare function boolean(): Struct<boolean, null>;
386/**
387 * Ensure that a value is a valid `Date`.
388 *
389 * Note: this also ensures that the value is *not* an invalid `Date` object,
390 * which can occur when parsing a date fails but still returns a `Date`.
391 */
392declare function date(): Struct<Date, null>;
393/**
394 * Ensure that a value is one of a set of potential values.
395 *
396 * Note: after creating the struct, you can access the definition of the
397 * potential values as `struct.schema`.
398 */
399declare function enums<T extends number>(values: readonly T[]): Struct<T, {
400 [K in T[][number]]: K;
401}>;
402declare function enums<T extends string>(values: readonly T[]): Struct<T, {
403 [K in T[][number]]: K;
404}>;
405/**
406 * Ensure that a value is a function.
407 */
408declare function func(): Struct<Function, null>;
409/**
410 * Ensure that a value is an instance of a specific class.
411 */
412declare function instance<T extends {
413 new (...args: any): any;
414}>(Class: T): Struct<InstanceType<T>, null>;
415/**
416 * Ensure that a value is an integer.
417 */
418declare function integer(): Struct<number, null>;
419/**
420 * Ensure that a value matches all of a set of types.
421 */
422declare function intersection<A extends AnyStruct, B extends AnyStruct[]>(Structs: [
423 A,
424 ...B
425]): Struct<Infer<A> & UnionToIntersection<InferStructTuple<B>[number]>, null>;
426/**
427 * Ensure that a value is an exact value, using `===` for comparison.
428 */
429declare function literal<T extends boolean>(constant: T): Struct<T, T>;
430declare function literal<T extends number>(constant: T): Struct<T, T>;
431declare function literal<T extends string>(constant: T): Struct<T, T>;
432declare function literal<T>(constant: T): Struct<T, null>;
433/**
434 * Ensure that a value is a `Map` object, and that its keys and values are of
435 * specific types.
436 */
437declare function map(): Struct<Map<unknown, unknown>, null>;
438declare function map<K, V>(Key: Struct<K>, Value: Struct<V>): Struct<Map<K, V>, null>;
439/**
440 * Ensure that no value ever passes validation.
441 */
442declare function never(): Struct<never, null>;
443/**
444 * Augment an existing struct to allow `null` values.
445 */
446declare function nullable<T, S>(struct: Struct<T, S>): Struct<T | null, S>;
447/**
448 * Ensure that a value is a number.
449 */
450declare function number(): Struct<number, null>;
451/**
452 * Ensure that a value is an object, that is has a known set of properties,
453 * and that its properties are of specific types.
454 *
455 * Note: Unrecognized properties will fail validation.
456 */
457declare function object(): Struct<Record<string, unknown>, null>;
458declare function object<S extends ObjectSchema>(schema: S): Struct<ObjectType<S>, S>;
459/**
460 * Augment a struct to allow `undefined` values.
461 */
462declare function optional<T, S>(struct: Struct<T, S>): Struct<T | undefined, S>;
463/**
464 * Ensure that a value is an object with keys and values of specific types, but
465 * without ensuring any specific shape of properties.
466 *
467 * Like TypeScript's `Record` utility.
468 */
469declare function record<K extends string, V>(Key: Struct<K>, Value: Struct<V>): Struct<Record<K, V>, null>;
470/**
471 * Ensure that a value is a `RegExp`.
472 *
473 * Note: this does not test the value against the regular expression! For that
474 * you need to use the `pattern()` refinement.
475 */
476declare function regexp(): Struct<RegExp, null>;
477/**
478 * Ensure that a value is a `Set` object, and that its elements are of a
479 * specific type.
480 */
481declare function set(): Struct<Set<unknown>, null>;
482declare function set<T>(Element: Struct<T>): Struct<Set<T>, null>;
483/**
484 * Ensure that a value is a string.
485 */
486declare function string(): Struct<string, null>;
487/**
488 * Ensure that a value is a tuple of a specific length, and that each of its
489 * elements is of a specific type.
490 */
491declare function tuple<A extends AnyStruct, B extends AnyStruct[]>(Structs: [
492 A,
493 ...B
494]): Struct<[
495 Infer<A>,
496 ...InferStructTuple<B>
497], null>;
498/**
499 * Ensure that a value has a set of known properties of specific types.
500 *
501 * Note: Unrecognized properties are allowed and untouched. This is similar to
502 * how TypeScript's structural typing works.
503 */
504declare function type<S extends ObjectSchema>(schema: S): Struct<ObjectType<S>, S>;
505/**
506 * Ensure that a value matches one of a set of types.
507 */
508declare function union<A extends AnyStruct, B extends AnyStruct[]>(Structs: [
509 A,
510 ...B
511]): Struct<Infer<A> | InferStructTuple<B>[number], null>;
512/**
513 * Ensure that any value passes validation, without widening its type to `any`.
514 */
515declare function unknown(): Struct<unknown, null>;
516/**
517 * Create a new struct that combines the properties properties from multiple
518 * object or type structs. Its return type will match the first parameter's type.
519 *
520 * Like JavaScript's `Object.assign` utility.
521 */
522declare function assign<A extends ObjectSchema, B extends ObjectSchema>(A: Struct<ObjectType<A>, A>, B: Struct<ObjectType<B>, B>): Struct<ObjectType<Assign<A, B>>, Assign<A, B>>;
523declare function assign<A extends ObjectSchema, B extends ObjectSchema, C extends ObjectSchema>(A: Struct<ObjectType<A>, A>, B: Struct<ObjectType<B>, B>, C: Struct<ObjectType<C>, C>): Struct<ObjectType<Assign<Assign<A, B>, C>>, Assign<Assign<A, B>, C>>;
524declare function assign<A extends ObjectSchema, B extends ObjectSchema, C extends ObjectSchema, D extends ObjectSchema>(A: Struct<ObjectType<A>, A>, B: Struct<ObjectType<B>, B>, C: Struct<ObjectType<C>, C>, D: Struct<ObjectType<D>, D>): Struct<ObjectType<Assign<Assign<Assign<A, B>, C>, D>>, Assign<Assign<Assign<A, B>, C>, D>>;
525declare function assign<A extends ObjectSchema, B extends ObjectSchema, C extends ObjectSchema, D extends ObjectSchema, E extends ObjectSchema>(A: Struct<ObjectType<A>, A>, B: Struct<ObjectType<B>, B>, C: Struct<ObjectType<C>, C>, D: Struct<ObjectType<D>, D>, E: Struct<ObjectType<E>, E>): Struct<ObjectType<Assign<Assign<Assign<Assign<A, B>, C>, D>, E>>, Assign<Assign<Assign<Assign<A, B>, C>, D>, E>>;
526/**
527 * Define a new struct type with a custom validation function.
528 */
529declare function define<T>(name: string, validator: Validator): Struct<T, null>;
530/**
531 * Create a new struct based on an existing struct, but the value is allowed to
532 * be `undefined`. `log` will be called if the value is not `undefined`.
533 */
534declare function deprecated<T>(struct: Struct<T>, log: (value: unknown, ctx: Context) => void): Struct<T>;
535/**
536 * Create a struct with dynamic validation logic.
537 *
538 * The callback will receive the value currently being validated, and must
539 * return a struct object to validate it with. This can be useful to model
540 * validation logic that changes based on its input.
541 */
542declare function dynamic<T>(fn: (value: unknown, ctx: Context) => Struct<T, any>): Struct<T, null>;
543/**
544 * Create a struct with lazily evaluated validation logic.
545 *
546 * The first time validation is run with the struct, the callback will be called
547 * and must return a struct object to use. This is useful for cases where you
548 * want to have self-referential structs for nested data structures to avoid a
549 * circular definition problem.
550 */
551declare function lazy<T>(fn: () => Struct<T, any>): Struct<T, null>;
552/**
553 * Create a new struct based on an existing object struct, but excluding
554 * specific properties.
555 *
556 * Like TypeScript's `Omit` utility.
557 */
558declare function omit<S extends ObjectSchema, K extends keyof S>(struct: Struct<ObjectType<S>, S>, keys: K[]): Struct<ObjectType<Omit<S, K>>, Omit<S, K>>;
559/**
560 * Create a new struct based on an existing object struct, but with all of its
561 * properties allowed to be `undefined`.
562 *
563 * Like TypeScript's `Partial` utility.
564 */
565declare function partial<S extends ObjectSchema>(struct: Struct<ObjectType<S>, S> | S): Struct<ObjectType<PartialObjectSchema<S>>, PartialObjectSchema<S>>;
566/**
567 * Create a new struct based on an existing object struct, but only including
568 * specific properties.
569 *
570 * Like TypeScript's `Pick` utility.
571 */
572declare function pick<S extends ObjectSchema, K extends keyof S>(struct: Struct<ObjectType<S>, S>, keys: K[]): Struct<ObjectType<Pick<S, K>>, Pick<S, K>>;
573/**
574 * Define a new struct type with a custom validation function.
575 *
576 * @deprecated This function has been renamed to `define`.
577 */
578declare function struct<T>(name: string, validator: Validator): Struct<T, null>;
579export { Failure, StructError, Struct, assert, create, mask, is, validate, Context, Infer, Describe, Result, Coercer, Validator, Refiner, coerce, defaulted, trimmed, empty, max, min, nonempty, pattern, size, refine, any, array, bigint, boolean, date, enums, func, instance, integer, intersection, literal, map, never, nullable, number, object, optional, record, regexp, set, string, tuple, type, union, unknown, assign, define, deprecated, dynamic, lazy, omit, partial, pick, struct };