UNPKG

zod

Version:

TypeScript-first schema declaration and validation library with static type inference

129 lines (107 loc) 4.15 kB
import type * as errors from "./errors.js"; import type * as schemas from "./schemas.js"; import type { Class } from "./util.js"; ////////////////////////////// CONSTRUCTORS /////////////////////////////////////// type ZodTrait = { _zod: { def: any; [k: string]: any } }; export interface $constructor<T extends ZodTrait, D = T["_zod"]["def"]> { new (def: D): T; init(inst: T, def: D): asserts inst is T; } /** A special constant with type `never` */ export const NEVER: never = Object.freeze({ status: "aborted", }) as never; export /*@__NO_SIDE_EFFECTS__*/ function $constructor<T extends ZodTrait, D = T["_zod"]["def"]>( name: string, initializer: (inst: T, def: D) => void, params?: { Parent?: typeof Class } ): $constructor<T, D> { function init(inst: T, def: D) { if (!inst._zod) { Object.defineProperty(inst, "_zod", { value: { def, constr: _, traits: new Set(), }, enumerable: false, }); } if (inst._zod.traits.has(name)) { return; } inst._zod.traits.add(name); initializer(inst, def); // support prototype modifications const proto = _.prototype; const keys = Object.keys(proto); for (let i = 0; i < keys.length; i++) { const k = keys[i]!; if (!(k in inst)) { (inst as any)[k] = proto[k].bind(inst); } } } // doesn't work if Parent has a constructor with arguments const Parent = params?.Parent ?? Object; class Definition extends Parent {} Object.defineProperty(Definition, "name", { value: name }); function _(this: any, def: D) { const inst = params?.Parent ? new Definition() : this; init(inst, def); inst._zod.deferred ??= []; for (const fn of inst._zod.deferred) { fn(); } return inst; } Object.defineProperty(_, "init", { value: init }); Object.defineProperty(_, Symbol.hasInstance, { value: (inst: any) => { if (params?.Parent && inst instanceof params.Parent) return true; return inst?._zod?.traits?.has(name); }, }); Object.defineProperty(_, "name", { value: name }); return _ as any; } ////////////////////////////// UTILITIES /////////////////////////////////////// export const $brand: unique symbol = Symbol("zod_brand"); export type $brand<T extends string | number | symbol = string | number | symbol> = { [$brand]: { [k in T]: true }; }; export type $ZodBranded<T extends schemas.SomeType, Brand extends string | number | symbol> = T & Record<"_zod", Record<"output", output<T> & $brand<Brand>>>; export class $ZodAsyncError extends Error { constructor() { super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`); } } export class $ZodEncodeError extends Error { constructor(name: string) { super(`Encountered unidirectional transform during encode: ${name}`); this.name = "ZodEncodeError"; } } //////////////////////////// TYPE HELPERS /////////////////////////////////// // export type input<T extends schemas.$ZodType> = T["_zod"]["input"]; // export type output<T extends schemas.$ZodType> = T["_zod"]["output"]; // export type input<T extends schemas.$ZodType> = T["_zod"]["input"]; // export type output<T extends schemas.$ZodType> = T["_zod"]["output"]; export type input<T> = T extends { _zod: { input: any } } ? T["_zod"]["input"] : unknown; export type output<T> = T extends { _zod: { output: any } } ? T["_zod"]["output"] : unknown; export type { output as infer }; ////////////////////////////// CONFIG /////////////////////////////////////// export interface $ZodConfig { /** Custom error map. Overrides `config().localeError`. */ customError?: errors.$ZodErrorMap | undefined; /** Localized error map. Lowest priority. */ localeError?: errors.$ZodErrorMap | undefined; /** Disable JIT schema compilation. Useful in environments that disallow `eval`. */ jitless?: boolean | undefined; } export const globalConfig: $ZodConfig = {}; export function config(newConfig?: Partial<$ZodConfig>): $ZodConfig { if (newConfig) Object.assign(globalConfig, newConfig); return globalConfig; }