From bf829bd82b41f0bb72629a71cdf67aafbe059814 Mon Sep 17 00:00:00 2001 From: Kartal Kaan Bozdogan Date: Sat, 12 Oct 2024 21:11:18 +0200 Subject: [PATCH 1/6] Make z.ZodType contravariant wrt. the input type --- src/types.ts | 246 +++++++++++++++++++++++++++------------------------ 1 file changed, 129 insertions(+), 117 deletions(-) diff --git a/src/types.ts b/src/types.ts index f89acb5e0..366fb9893 100644 --- a/src/types.ts +++ b/src/types.ts @@ -46,10 +46,12 @@ export interface RefinementCtx { path: (string | number)[]; } export type ZodRawShape = { [k: string]: ZodTypeAny }; -export type ZodTypeAny = ZodType; -export type TypeOf> = T["_output"]; -export type input> = T["_input"]; -export type output> = T["_output"]; +export type ZodTypeAny = ZodType | ZodType; +export type TypeOf = T["_output"]; +export type input = T extends ZodType + ? I + : never; +export type output = T["_output"]; export type { TypeOf as infer }; export type CustomErrorParams = Partial>; @@ -168,11 +170,11 @@ export type SafeParseReturnType = export abstract class ZodType< Output = any, Def extends ZodTypeDef = ZodTypeDef, - Input = Output + in Input = Output > { readonly _type!: Output; readonly _output!: Output; - readonly _input!: Input; + _input(_: Input): void {} readonly _def!: Def; get description() { @@ -236,68 +238,20 @@ export abstract class ZodType< } parse(data: unknown, params?: Partial): Output { - const result = this.safeParse(data, params); + const result = safeParse(this, data, params); if (result.success) return result.data; throw result.error; } - safeParse( - data: unknown, - params?: Partial - ): SafeParseReturnType { - const ctx: ParseContext = { - common: { - issues: [], - async: params?.async ?? false, - contextualErrorMap: params?.errorMap, - }, - path: params?.path || [], - schemaErrorMap: this._def.errorMap, - parent: null, - data, - parsedType: getParsedType(data), - }; - const result = this._parseSync({ data, path: ctx.path, parent: ctx }); - - return handleResult(ctx, result); - } - async parseAsync( data: unknown, params?: Partial ): Promise { - const result = await this.safeParseAsync(data, params); + const result = await safeParseAsync(this, data, params); if (result.success) return result.data; throw result.error; } - async safeParseAsync( - data: unknown, - params?: Partial - ): Promise> { - const ctx: ParseContext = { - common: { - issues: [], - contextualErrorMap: params?.errorMap, - async: true, - }, - path: params?.path || [], - schemaErrorMap: this._def.errorMap, - parent: null, - data, - parsedType: getParsedType(data), - }; - - const maybeAsyncResult = this._parse({ data, path: ctx.path, parent: ctx }); - const result = await (isAsync(maybeAsyncResult) - ? maybeAsyncResult - : Promise.resolve(maybeAsyncResult)); - return handleResult(ctx, result); - } - - /** Alias of safeParseAsync */ - spa = this.safeParseAsync; - refine( check: (arg: Output) => arg is RefinedOutput, message?: string | CustomErrorParams | ((arg: Output) => CustomErrorParams) @@ -399,10 +353,7 @@ export abstract class ZodType< constructor(def: Def) { this._def = def; this.parse = this.parse.bind(this); - this.safeParse = this.safeParse.bind(this); this.parseAsync = this.parseAsync.bind(this); - this.safeParseAsync = this.safeParseAsync.bind(this); - this.spa = this.spa.bind(this); this.refine = this.refine.bind(this); this.refinement = this.refinement.bind(this); this.superRefine = this.superRefine.bind(this); @@ -416,7 +367,6 @@ export abstract class ZodType< this.transform = this.transform.bind(this); this.brand = this.brand.bind(this); this.default = this.default.bind(this); - this.catch = this.catch.bind(this); this.describe = this.describe.bind(this); this.pipe = this.pipe.bind(this); this.readonly = this.readonly.bind(this); @@ -450,7 +400,7 @@ export abstract class ZodType< transform( transform: (arg: Output, ctx: RefinementCtx) => NewOut | Promise - ): ZodEffects { + ): ZodEffects { return new ZodEffects({ ...processCreateParams(this._def), schema: this, @@ -481,21 +431,6 @@ export abstract class ZodType< }); } - catch(def: Output): ZodCatch; - catch( - def: (ctx: { error: ZodError; input: Input }) => Output - ): ZodCatch; - catch(def: any) { - const catchValueFunc = typeof def === "function" ? def : () => def; - - return new ZodCatch({ - ...processCreateParams(this._def), - innerType: this, - catchValue: catchValueFunc, - typeName: ZodFirstPartyTypeKind.ZodCatch, - }) as any; - } - describe(description: string): this { const This = (this as any).constructor; return new This({ @@ -512,10 +447,10 @@ export abstract class ZodType< } isOptional(): boolean { - return this.safeParse(undefined).success; + return safeParse(this, undefined).success; } isNullable(): boolean { - return this.safeParse(null).success; + return safeParse(this, null).success; } } @@ -2167,9 +2102,7 @@ export class ZodArray< > extends ZodType< arrayOutputType, ZodArrayDef, - Cardinality extends "atleastone" - ? [T["_input"], ...T["_input"][]] - : T["_input"][] + Cardinality extends "atleastone" ? [input, ...input[]] : input[] > { _parse(input: ParseInput): ParseReturnType { const { ctx, status } = this._processInputParams(input); @@ -2349,16 +2282,16 @@ export type objectInputType< PassthroughType; export type baseObjectInputType = objectUtil.addQuestionMarks<{ - [k in keyof Shape]: Shape[k]["_input"]; + [k in keyof Shape]: input; }>; -export type CatchallOutput = ZodType extends T +export type CatchallOutput = ZodType extends T ? unknown : { [k: string]: T["_output"] }; -export type CatchallInput = ZodType extends T +export type CatchallInput = ZodType extends T ? unknown - : { [k: string]: T["_input"] }; + : { [k: string]: input }; export type PassthroughType = T extends "passthrough" ? { [k: string]: unknown } : unknown; @@ -2619,7 +2552,7 @@ export class ZodObject< // }>, // NewInput extends util.flatten<{ // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation - // ? Augmentation[k]["_input"] + // ? input // : k extends keyof Input // ? Input[k] // : never; @@ -2681,7 +2614,7 @@ export class ZodObject< // }, // NewInput extends { // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation - // ? Augmentation[k]["_input"] + // ? input // : k extends keyof Input // ? Input[k] // : never; @@ -2928,7 +2861,7 @@ export interface ZodUnionDef< export class ZodUnion extends ZodType< T[number]["_output"], ZodUnionDef, - T[number]["_input"] + input > { _parse(input: ParseInput): ParseReturnType { const { ctx } = this._processInputParams(input); @@ -3092,7 +3025,7 @@ const getDiscriminator = (type: T): Primitive[] => { export type ZodDiscriminatedUnionOption = ZodObject< - { [key in Discriminator]: ZodTypeAny } & ZodRawShape, + { [key in Discriminator]: ZodTypeAny }, UnknownKeysParam, ZodTypeAny >; @@ -3303,7 +3236,7 @@ export class ZodIntersection< > extends ZodType< T["_output"] & U["_output"], ZodIntersectionDef, - T["_input"] & U["_input"] + input & input > { _parse(input: ParseInput): ParseReturnType { const { status, ctx } = this._processInputParams(input); @@ -3384,7 +3317,7 @@ export class ZodIntersection< export type ZodTupleItems = [ZodTypeAny, ...ZodTypeAny[]]; export type AssertArray = T extends any[] ? T : never; export type OutputTypeOfTuple = AssertArray<{ - [k in keyof T]: T[k] extends ZodType ? T[k]["_output"] : never; + [k in keyof T]: T[k] extends ZodTypeAny ? T[k]["_output"] : never; }>; export type OutputTypeOfTupleWithRest< T extends ZodTupleItems | [], @@ -3394,13 +3327,13 @@ export type OutputTypeOfTupleWithRest< : OutputTypeOfTuple; export type InputTypeOfTuple = AssertArray<{ - [k in keyof T]: T[k] extends ZodType ? T[k]["_input"] : never; + [k in keyof T]: T[k] extends ZodTypeAny ? input : never; }>; export type InputTypeOfTupleWithRest< T extends ZodTupleItems | [], Rest extends ZodTypeAny | null = null > = Rest extends ZodTypeAny - ? [...InputTypeOfTuple, ...Rest["_input"][]] + ? [...InputTypeOfTuple, ...input[]] : InputTypeOfTuple; export interface ZodTupleDef< @@ -3540,7 +3473,7 @@ export class ZodRecord< > extends ZodType< RecordType, ZodRecordDef, - RecordType + RecordType, input> > { get keySchema() { return this._def.keyType; @@ -3639,7 +3572,7 @@ export class ZodMap< > extends ZodType< Map, ZodMapDef, - Map + Map, input> > { get keySchema() { return this._def.keyType; @@ -3743,7 +3676,7 @@ export interface ZodSetDef export class ZodSet extends ZodType< Set, ZodSetDef, - Set + Set> > { _parse(input: ParseInput): ParseReturnType { const { status, ctx } = this._processInputParams(input); @@ -3864,15 +3797,15 @@ export interface ZodFunctionDef< export type OuterTypeOfFunction< Args extends ZodTuple, Returns extends ZodTypeAny -> = Args["_input"] extends Array - ? (...args: Args["_input"]) => Returns["_output"] +> = input extends Array + ? (...args: input) => Returns["_output"] : never; export type InnerTypeOfFunction< Args extends ZodTuple, Returns extends ZodTypeAny > = Args["_output"] extends Array - ? (...args: Args["_output"]) => Returns["_input"] + ? (...args: Args["_output"]) => input : never; export class ZodFunction< @@ -3961,12 +3894,12 @@ export class ZodFunction< // eslint-disable-next-line @typescript-eslint/no-this-alias const me = this; return OK(function (this: any, ...args: any[]) { - const parsedArgs = me._def.args.safeParse(args, params); + const parsedArgs = safeParse(me._def.args, args, params); if (!parsedArgs.success) { throw new ZodError([makeArgsIssue(args, parsedArgs.error)]); } const result = Reflect.apply(fn, this, parsedArgs.data); - const parsedReturns = me._def.returns.safeParse(result, params); + const parsedReturns = safeParse(me._def.returns, result, params); if (!parsedReturns.success) { throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]); } @@ -3992,7 +3925,7 @@ export class ZodFunction< }); } - returns>( + returns( returnType: NewReturnType ): ZodFunction { return new ZodFunction({ @@ -4004,7 +3937,7 @@ export class ZodFunction< implement>( func: F ): ReturnType extends Returns["_output"] - ? (...args: Args["_input"]) => ReturnType + ? (...args: input) => ReturnType : OuterTypeOfFunction { const validatedFunc = this.parse(func); return validatedFunc as any; @@ -4365,7 +4298,7 @@ export interface ZodPromiseDef export class ZodPromise extends ZodType< Promise, ZodPromiseDef, - Promise + Promise> > { unwrap() { return this._def.type; @@ -4637,7 +4570,7 @@ export type ZodOptionalType = ZodOptional; export class ZodOptional extends ZodType< T["_output"] | undefined, ZodOptionalDef, - T["_input"] | undefined + input | undefined > { _parse(input: ParseInput): ParseReturnType { const parsedType = this._getType(input); @@ -4681,7 +4614,7 @@ export type ZodNullableType = ZodNullable; export class ZodNullable extends ZodType< T["_output"] | null, ZodNullableDef, - T["_input"] | null + input | null > { _parse(input: ParseInput): ParseReturnType { const parsedType = this._getType(input); @@ -4717,14 +4650,14 @@ export class ZodNullable extends ZodType< export interface ZodDefaultDef extends ZodTypeDef { innerType: T; - defaultValue: () => util.noUndefined; + defaultValue: () => util.noUndefined>; typeName: ZodFirstPartyTypeKind.ZodDefault; } export class ZodDefault extends ZodType< util.noUndefined, ZodDefaultDef, - T["_input"] | undefined + input | undefined > { _parse(input: ParseInput): ParseReturnType { const { ctx } = this._processInputParams(input); @@ -4746,7 +4679,7 @@ export class ZodDefault extends ZodType< static create = ( type: T, params: RawCreateParams & { - default: T["_input"] | (() => util.noUndefined); + default: input | (() => util.noUndefined>); } ): ZodDefault => { return new ZodDefault({ @@ -4754,7 +4687,7 @@ export class ZodDefault extends ZodType< typeName: ZodFirstPartyTypeKind.ZodDefault, defaultValue: typeof params.default === "function" - ? params.default + ? (params.default as any) : () => params.default as any, ...processCreateParams(params), }) as any; @@ -4771,14 +4704,14 @@ export class ZodDefault extends ZodType< export interface ZodCatchDef extends ZodTypeDef { innerType: T; - catchValue: (ctx: { error: ZodError; input: unknown }) => T["_input"]; + catchValue: (ctx: { error: ZodError; input: unknown }) => input; typeName: ZodFirstPartyTypeKind.ZodCatch; } export class ZodCatch extends ZodType< T["_output"], ZodCatchDef, - unknown // any input will pass validation // T["_input"] + unknown // any input will pass validation // input > { _parse(input: ParseInput): ParseReturnType { const { ctx } = this._processInputParams(input); @@ -4845,7 +4778,9 @@ export class ZodCatch extends ZodType< innerType: type, typeName: ZodFirstPartyTypeKind.ZodCatch, catchValue: - typeof params.catch === "function" ? params.catch : () => params.catch, + typeof params.catch === "function" + ? (params.catch as any) + : () => params.catch, ...processCreateParams(params), }); }; @@ -4908,7 +4843,7 @@ export type BRAND = { export class ZodBranded< T extends ZodTypeAny, B extends string | number | symbol -> extends ZodType, ZodBrandedDef, T["_input"]> { +> extends ZodType, ZodBrandedDef, input> { _parse(input: ParseInput): ParseReturnType { const { ctx } = this._processInputParams(input); const data = ctx.data; @@ -4942,7 +4877,7 @@ export interface ZodPipelineDef export class ZodPipeline< A extends ZodTypeAny, B extends ZodTypeAny -> extends ZodType, A["_input"]> { +> extends ZodType, input> { _parse(input: ParseInput): ParseReturnType { const { status, ctx } = this._processInputParams(input); if (ctx.common.async) { @@ -5037,7 +4972,7 @@ export interface ZodReadonlyDef export class ZodReadonly extends ZodType< MakeReadonly, ZodReadonlyDef, - MakeReadonly + MakeReadonly> > { _parse(input: ParseInput): ParseReturnType { const result = this._def.innerType._parse(input); @@ -5178,7 +5113,7 @@ export type ZodFirstPartySchemaTypes = | ZodLazy | ZodLiteral | ZodEnum - | ZodEffects + | ZodEffects | ZodNativeEnum | ZodOptional | ZodNullable @@ -5256,6 +5191,83 @@ export const coerce = { ZodDate.create({ ...arg, coerce: true })) as (typeof ZodDate)["create"], }; +export function safeParse( + schema: ZodType, + data: unknown, + params?: Partial +): SafeParseReturnType { + const ctx: ParseContext = { + common: { + issues: [], + async: params?.async ?? false, + contextualErrorMap: params?.errorMap, + }, + path: params?.path || [], + schemaErrorMap: schema._def.errorMap, + parent: null, + data, + parsedType: getParsedType(data), + }; + const result = schema._parseSync({ data, path: ctx.path, parent: ctx }); + + return handleResult(ctx, result); +} + +export async function safeParseAsync( + schema: ZodType, + data: unknown, + params?: Partial +): Promise> { + const ctx: ParseContext = { + common: { + issues: [], + contextualErrorMap: params?.errorMap, + async: true, + }, + path: params?.path || [], + schemaErrorMap: schema._def.errorMap, + parent: null, + data, + parsedType: getParsedType(data), + }; + const maybeAsyncResult = schema._parse({ data, path: ctx.path, parent: ctx }); + const result = await (isAsync(maybeAsyncResult) + ? maybeAsyncResult + : Promise.resolve(maybeAsyncResult)); + return handleResult(ctx, result); +} + +/** Alias of safeParseAsync */ +export const spa = safeParseAsync; + +export function catch_< + Output, + Input, + Schema extends ZodType +>(schema: Schema, def: Output): ZodCatch; +export function catch_< + Output, + Input, + Schema extends ZodType +>( + schema: Schema, + def: (ctx: { error: ZodError; input: Input }) => Output +): ZodCatch; +export function catch_< + Output, + Input, + Schema extends ZodType +>(schema: Schema, def: any) { + const catchValueFunc = typeof def === "function" ? def : () => def; + + return new ZodCatch({ + ...processCreateParams(schema._def), + innerType: schema, + catchValue: catchValueFunc, + typeName: ZodFirstPartyTypeKind.ZodCatch, + }) as any; +} + export { anyType as any, arrayType as array, From 05c1f06b28b63067b154b30e17a2e32dacb235ee Mon Sep 17 00:00:00 2001 From: Kartal Kaan Bozdogan Date: Sat, 12 Oct 2024 23:38:18 +0200 Subject: [PATCH 2/6] Fix --- deno/lib/types.ts | 254 ++++++++++++++++++++++++---------------------- src/types.ts | 12 ++- 2 files changed, 141 insertions(+), 125 deletions(-) diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 9a6311289..1eef61f14 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -46,10 +46,12 @@ export interface RefinementCtx { path: (string | number)[]; } export type ZodRawShape = { [k: string]: ZodTypeAny }; -export type ZodTypeAny = ZodType; -export type TypeOf> = T["_output"]; -export type input> = T["_input"]; -export type output> = T["_output"]; +export type ZodTypeAny = ZodType | ZodType; +export type TypeOf = T["_output"]; +export type input = T extends ZodType + ? I + : never; +export type output = T["_output"]; export type { TypeOf as infer }; export type CustomErrorParams = Partial>; @@ -168,11 +170,11 @@ export type SafeParseReturnType = export abstract class ZodType< Output = any, Def extends ZodTypeDef = ZodTypeDef, - Input = Output + /*in*/ Input = Output > { readonly _type!: Output; readonly _output!: Output; - readonly _input!: Input; + readonly _input!: (_: Input) => void; readonly _def!: Def; get description() { @@ -236,68 +238,20 @@ export abstract class ZodType< } parse(data: unknown, params?: Partial): Output { - const result = this.safeParse(data, params); + const result = safeParse(this, data, params); if (result.success) return result.data; throw result.error; } - safeParse( - data: unknown, - params?: Partial - ): SafeParseReturnType { - const ctx: ParseContext = { - common: { - issues: [], - async: params?.async ?? false, - contextualErrorMap: params?.errorMap, - }, - path: params?.path || [], - schemaErrorMap: this._def.errorMap, - parent: null, - data, - parsedType: getParsedType(data), - }; - const result = this._parseSync({ data, path: ctx.path, parent: ctx }); - - return handleResult(ctx, result); - } - async parseAsync( data: unknown, params?: Partial ): Promise { - const result = await this.safeParseAsync(data, params); + const result = await safeParseAsync(this, data, params); if (result.success) return result.data; throw result.error; } - async safeParseAsync( - data: unknown, - params?: Partial - ): Promise> { - const ctx: ParseContext = { - common: { - issues: [], - contextualErrorMap: params?.errorMap, - async: true, - }, - path: params?.path || [], - schemaErrorMap: this._def.errorMap, - parent: null, - data, - parsedType: getParsedType(data), - }; - - const maybeAsyncResult = this._parse({ data, path: ctx.path, parent: ctx }); - const result = await (isAsync(maybeAsyncResult) - ? maybeAsyncResult - : Promise.resolve(maybeAsyncResult)); - return handleResult(ctx, result); - } - - /** Alias of safeParseAsync */ - spa = this.safeParseAsync; - refine( check: (arg: Output) => arg is RefinedOutput, message?: string | CustomErrorParams | ((arg: Output) => CustomErrorParams) @@ -399,10 +353,7 @@ export abstract class ZodType< constructor(def: Def) { this._def = def; this.parse = this.parse.bind(this); - this.safeParse = this.safeParse.bind(this); this.parseAsync = this.parseAsync.bind(this); - this.safeParseAsync = this.safeParseAsync.bind(this); - this.spa = this.spa.bind(this); this.refine = this.refine.bind(this); this.refinement = this.refinement.bind(this); this.superRefine = this.superRefine.bind(this); @@ -416,7 +367,6 @@ export abstract class ZodType< this.transform = this.transform.bind(this); this.brand = this.brand.bind(this); this.default = this.default.bind(this); - this.catch = this.catch.bind(this); this.describe = this.describe.bind(this); this.pipe = this.pipe.bind(this); this.readonly = this.readonly.bind(this); @@ -450,7 +400,7 @@ export abstract class ZodType< transform( transform: (arg: Output, ctx: RefinementCtx) => NewOut | Promise - ): ZodEffects { + ): ZodEffects { return new ZodEffects({ ...processCreateParams(this._def), schema: this, @@ -481,21 +431,6 @@ export abstract class ZodType< }); } - catch(def: Output): ZodCatch; - catch( - def: (ctx: { error: ZodError; input: Input }) => Output - ): ZodCatch; - catch(def: any) { - const catchValueFunc = typeof def === "function" ? def : () => def; - - return new ZodCatch({ - ...processCreateParams(this._def), - innerType: this, - catchValue: catchValueFunc, - typeName: ZodFirstPartyTypeKind.ZodCatch, - }) as any; - } - describe(description: string): this { const This = (this as any).constructor; return new This({ @@ -512,10 +447,10 @@ export abstract class ZodType< } isOptional(): boolean { - return this.safeParse(undefined).success; + return safeParse(this, undefined).success; } isNullable(): boolean { - return this.safeParse(null).success; + return safeParse(this, null).success; } } @@ -2167,9 +2102,7 @@ export class ZodArray< > extends ZodType< arrayOutputType, ZodArrayDef, - Cardinality extends "atleastone" - ? [T["_input"], ...T["_input"][]] - : T["_input"][] + Cardinality extends "atleastone" ? [input, ...input[]] : input[] > { _parse(input: ParseInput): ParseReturnType { const { ctx, status } = this._processInputParams(input); @@ -2349,16 +2282,16 @@ export type objectInputType< PassthroughType; export type baseObjectInputType = objectUtil.addQuestionMarks<{ - [k in keyof Shape]: Shape[k]["_input"]; + [k in keyof Shape]: input; }>; -export type CatchallOutput = ZodType extends T +export type CatchallOutput = ZodType extends T ? unknown : { [k: string]: T["_output"] }; -export type CatchallInput = ZodType extends T +export type CatchallInput = ZodType extends T ? unknown - : { [k: string]: T["_input"] }; + : { [k: string]: input }; export type PassthroughType = T extends "passthrough" ? { [k: string]: unknown } : unknown; @@ -2619,7 +2552,7 @@ export class ZodObject< // }>, // NewInput extends util.flatten<{ // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation - // ? Augmentation[k]["_input"] + // ? input // : k extends keyof Input // ? Input[k] // : never; @@ -2681,7 +2614,7 @@ export class ZodObject< // }, // NewInput extends { // [k in keyof Augmentation | keyof Input]: k extends keyof Augmentation - // ? Augmentation[k]["_input"] + // ? input // : k extends keyof Input // ? Input[k] // : never; @@ -2928,7 +2861,7 @@ export interface ZodUnionDef< export class ZodUnion extends ZodType< T[number]["_output"], ZodUnionDef, - T[number]["_input"] + input > { _parse(input: ParseInput): ParseReturnType { const { ctx } = this._processInputParams(input); @@ -3092,14 +3025,16 @@ const getDiscriminator = (type: T): Primitive[] => { export type ZodDiscriminatedUnionOption = ZodObject< - { [key in Discriminator]: ZodTypeAny } & ZodRawShape, + { [key in Discriminator]: ZodTypeAny }, UnknownKeysParam, - ZodTypeAny + ZodTypeAny, + any, + never >; export interface ZodDiscriminatedUnionDef< Discriminator extends string, - Options extends ZodDiscriminatedUnionOption[] = ZodDiscriminatedUnionOption[] + Options extends ZodDiscriminatedUnionOption[] = ZodDiscriminatedUnionOption[] > extends ZodTypeDef { discriminator: Discriminator; options: Options; @@ -3220,7 +3155,7 @@ export class ZodDiscriminatedUnion< typeName: ZodFirstPartyTypeKind.ZodDiscriminatedUnion, discriminator, options, - optionsMap, + optionsMap: optionsMap as any, ...processCreateParams(params), }); } @@ -3303,7 +3238,7 @@ export class ZodIntersection< > extends ZodType< T["_output"] & U["_output"], ZodIntersectionDef, - T["_input"] & U["_input"] + input & input > { _parse(input: ParseInput): ParseReturnType { const { status, ctx } = this._processInputParams(input); @@ -3384,7 +3319,7 @@ export class ZodIntersection< export type ZodTupleItems = [ZodTypeAny, ...ZodTypeAny[]]; export type AssertArray = T extends any[] ? T : never; export type OutputTypeOfTuple = AssertArray<{ - [k in keyof T]: T[k] extends ZodType ? T[k]["_output"] : never; + [k in keyof T]: T[k] extends ZodTypeAny ? T[k]["_output"] : never; }>; export type OutputTypeOfTupleWithRest< T extends ZodTupleItems | [], @@ -3394,13 +3329,13 @@ export type OutputTypeOfTupleWithRest< : OutputTypeOfTuple; export type InputTypeOfTuple = AssertArray<{ - [k in keyof T]: T[k] extends ZodType ? T[k]["_input"] : never; + [k in keyof T]: T[k] extends ZodTypeAny ? input : never; }>; export type InputTypeOfTupleWithRest< T extends ZodTupleItems | [], Rest extends ZodTypeAny | null = null > = Rest extends ZodTypeAny - ? [...InputTypeOfTuple, ...Rest["_input"][]] + ? [...InputTypeOfTuple, ...input[]] : InputTypeOfTuple; export interface ZodTupleDef< @@ -3540,7 +3475,7 @@ export class ZodRecord< > extends ZodType< RecordType, ZodRecordDef, - RecordType + RecordType, input> > { get keySchema() { return this._def.keyType; @@ -3639,7 +3574,7 @@ export class ZodMap< > extends ZodType< Map, ZodMapDef, - Map + Map, input> > { get keySchema() { return this._def.keyType; @@ -3743,7 +3678,7 @@ export interface ZodSetDef export class ZodSet extends ZodType< Set, ZodSetDef, - Set + Set> > { _parse(input: ParseInput): ParseReturnType { const { status, ctx } = this._processInputParams(input); @@ -3864,15 +3799,15 @@ export interface ZodFunctionDef< export type OuterTypeOfFunction< Args extends ZodTuple, Returns extends ZodTypeAny -> = Args["_input"] extends Array - ? (...args: Args["_input"]) => Returns["_output"] +> = input extends Array + ? (...args: input) => Returns["_output"] : never; export type InnerTypeOfFunction< Args extends ZodTuple, Returns extends ZodTypeAny > = Args["_output"] extends Array - ? (...args: Args["_output"]) => Returns["_input"] + ? (...args: Args["_output"]) => input : never; export class ZodFunction< @@ -3961,12 +3896,12 @@ export class ZodFunction< // eslint-disable-next-line @typescript-eslint/no-this-alias const me = this; return OK(function (this: any, ...args: any[]) { - const parsedArgs = me._def.args.safeParse(args, params); + const parsedArgs = safeParse(me._def.args, args, params); if (!parsedArgs.success) { throw new ZodError([makeArgsIssue(args, parsedArgs.error)]); } const result = Reflect.apply(fn, this, parsedArgs.data); - const parsedReturns = me._def.returns.safeParse(result, params); + const parsedReturns = safeParse(me._def.returns, result, params); if (!parsedReturns.success) { throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]); } @@ -3992,7 +3927,7 @@ export class ZodFunction< }); } - returns>( + returns( returnType: NewReturnType ): ZodFunction { return new ZodFunction({ @@ -4004,7 +3939,7 @@ export class ZodFunction< implement>( func: F ): ReturnType extends Returns["_output"] - ? (...args: Args["_input"]) => ReturnType + ? (...args: input) => ReturnType : OuterTypeOfFunction { const validatedFunc = this.parse(func); return validatedFunc as any; @@ -4365,7 +4300,7 @@ export interface ZodPromiseDef export class ZodPromise extends ZodType< Promise, ZodPromiseDef, - Promise + Promise> > { unwrap() { return this._def.type; @@ -4637,7 +4572,7 @@ export type ZodOptionalType = ZodOptional; export class ZodOptional extends ZodType< T["_output"] | undefined, ZodOptionalDef, - T["_input"] | undefined + input | undefined > { _parse(input: ParseInput): ParseReturnType { const parsedType = this._getType(input); @@ -4681,7 +4616,7 @@ export type ZodNullableType = ZodNullable; export class ZodNullable extends ZodType< T["_output"] | null, ZodNullableDef, - T["_input"] | null + input | null > { _parse(input: ParseInput): ParseReturnType { const parsedType = this._getType(input); @@ -4717,14 +4652,14 @@ export class ZodNullable extends ZodType< export interface ZodDefaultDef extends ZodTypeDef { innerType: T; - defaultValue: () => util.noUndefined; + defaultValue: () => util.noUndefined>; typeName: ZodFirstPartyTypeKind.ZodDefault; } export class ZodDefault extends ZodType< util.noUndefined, ZodDefaultDef, - T["_input"] | undefined + input | undefined > { _parse(input: ParseInput): ParseReturnType { const { ctx } = this._processInputParams(input); @@ -4746,7 +4681,7 @@ export class ZodDefault extends ZodType< static create = ( type: T, params: RawCreateParams & { - default: T["_input"] | (() => util.noUndefined); + default: input | (() => util.noUndefined>); } ): ZodDefault => { return new ZodDefault({ @@ -4754,7 +4689,7 @@ export class ZodDefault extends ZodType< typeName: ZodFirstPartyTypeKind.ZodDefault, defaultValue: typeof params.default === "function" - ? params.default + ? (params.default as any) : () => params.default as any, ...processCreateParams(params), }) as any; @@ -4771,14 +4706,14 @@ export class ZodDefault extends ZodType< export interface ZodCatchDef extends ZodTypeDef { innerType: T; - catchValue: (ctx: { error: ZodError; input: unknown }) => T["_input"]; + catchValue: (ctx: { error: ZodError; input: unknown }) => input; typeName: ZodFirstPartyTypeKind.ZodCatch; } export class ZodCatch extends ZodType< T["_output"], ZodCatchDef, - unknown // any input will pass validation // T["_input"] + unknown // any input will pass validation // input > { _parse(input: ParseInput): ParseReturnType { const { ctx } = this._processInputParams(input); @@ -4845,7 +4780,9 @@ export class ZodCatch extends ZodType< innerType: type, typeName: ZodFirstPartyTypeKind.ZodCatch, catchValue: - typeof params.catch === "function" ? params.catch : () => params.catch, + typeof params.catch === "function" + ? (params.catch as any) + : () => params.catch, ...processCreateParams(params), }); }; @@ -4908,7 +4845,7 @@ export type BRAND = { export class ZodBranded< T extends ZodTypeAny, B extends string | number | symbol -> extends ZodType, ZodBrandedDef, T["_input"]> { +> extends ZodType, ZodBrandedDef, input> { _parse(input: ParseInput): ParseReturnType { const { ctx } = this._processInputParams(input); const data = ctx.data; @@ -4942,7 +4879,7 @@ export interface ZodPipelineDef export class ZodPipeline< A extends ZodTypeAny, B extends ZodTypeAny -> extends ZodType, A["_input"]> { +> extends ZodType, input> { _parse(input: ParseInput): ParseReturnType { const { status, ctx } = this._processInputParams(input); if (ctx.common.async) { @@ -5037,7 +4974,7 @@ export interface ZodReadonlyDef export class ZodReadonly extends ZodType< MakeReadonly, ZodReadonlyDef, - MakeReadonly + MakeReadonly> > { _parse(input: ParseInput): ParseReturnType { const result = this._def.innerType._parse(input); @@ -5178,7 +5115,7 @@ export type ZodFirstPartySchemaTypes = | ZodLazy | ZodLiteral | ZodEnum - | ZodEffects + | ZodEffects | ZodNativeEnum | ZodOptional | ZodNullable @@ -5256,6 +5193,83 @@ export const coerce = { ZodDate.create({ ...arg, coerce: true })) as (typeof ZodDate)["create"], }; +export function safeParse( + schema: ZodType, + data: unknown, + params?: Partial +): SafeParseReturnType { + const ctx: ParseContext = { + common: { + issues: [], + async: params?.async ?? false, + contextualErrorMap: params?.errorMap, + }, + path: params?.path || [], + schemaErrorMap: schema._def.errorMap, + parent: null, + data, + parsedType: getParsedType(data), + }; + const result = schema._parseSync({ data, path: ctx.path, parent: ctx }); + + return handleResult(ctx, result); +} + +export async function safeParseAsync( + schema: ZodType, + data: unknown, + params?: Partial +): Promise> { + const ctx: ParseContext = { + common: { + issues: [], + contextualErrorMap: params?.errorMap, + async: true, + }, + path: params?.path || [], + schemaErrorMap: schema._def.errorMap, + parent: null, + data, + parsedType: getParsedType(data), + }; + const maybeAsyncResult = schema._parse({ data, path: ctx.path, parent: ctx }); + const result = await (isAsync(maybeAsyncResult) + ? maybeAsyncResult + : Promise.resolve(maybeAsyncResult)); + return handleResult(ctx, result); +} + +/** Alias of safeParseAsync */ +export const spa = safeParseAsync; + +export function catch_< + Output, + Input, + Schema extends ZodType +>(schema: Schema, def: Output): ZodCatch; +export function catch_< + Output, + Input, + Schema extends ZodType +>( + schema: Schema, + def: (ctx: { error: ZodError; input: Input }) => Output +): ZodCatch; +export function catch_< + Output, + Input, + Schema extends ZodType +>(schema: Schema, def: any) { + const catchValueFunc = typeof def === "function" ? def : () => def; + + return new ZodCatch({ + ...processCreateParams(schema._def), + innerType: schema, + catchValue: catchValueFunc, + typeName: ZodFirstPartyTypeKind.ZodCatch, + }) as any; +} + export { anyType as any, arrayType as array, diff --git a/src/types.ts b/src/types.ts index 366fb9893..6873f05a9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -170,11 +170,11 @@ export type SafeParseReturnType = export abstract class ZodType< Output = any, Def extends ZodTypeDef = ZodTypeDef, - in Input = Output + /*in*/ Input = Output > { readonly _type!: Output; readonly _output!: Output; - _input(_: Input): void {} + readonly _input!: (_: Input) => void; readonly _def!: Def; get description() { @@ -3027,12 +3027,14 @@ export type ZodDiscriminatedUnionOption = ZodObject< { [key in Discriminator]: ZodTypeAny }, UnknownKeysParam, - ZodTypeAny + ZodTypeAny, + any, + never >; export interface ZodDiscriminatedUnionDef< Discriminator extends string, - Options extends ZodDiscriminatedUnionOption[] = ZodDiscriminatedUnionOption[] + Options extends ZodDiscriminatedUnionOption[] = ZodDiscriminatedUnionOption[] > extends ZodTypeDef { discriminator: Discriminator; options: Options; @@ -3153,7 +3155,7 @@ export class ZodDiscriminatedUnion< typeName: ZodFirstPartyTypeKind.ZodDiscriminatedUnion, discriminator, options, - optionsMap, + optionsMap: optionsMap as any, ...processCreateParams(params), }); } From 815e54addd8772bb9d3f136874df1431eee99428 Mon Sep 17 00:00:00 2001 From: Kartal Kaan Bozdogan Date: Sat, 12 Oct 2024 23:11:07 +0200 Subject: [PATCH 3/6] Fixed tests --- deno/lib/__tests__/all-errors.test.ts | 4 +- deno/lib/__tests__/array.test.ts | 2 +- deno/lib/__tests__/async-parsing.test.ts | 90 ++++++++++++------------ deno/lib/__tests__/base.test.ts | 10 ++- deno/lib/__tests__/catch.test.ts | 78 ++++++++++---------- deno/lib/__tests__/custom.test.ts | 2 +- deno/lib/__tests__/enum.test.ts | 13 ++-- deno/lib/__tests__/error.test.ts | 48 ++++++------- deno/lib/__tests__/generics.test.ts | 2 +- deno/lib/__tests__/instanceof.test.ts | 2 +- deno/lib/__tests__/intersection.test.ts | 8 +-- deno/lib/__tests__/literal.test.ts | 2 +- deno/lib/__tests__/map.test.ts | 20 +++--- deno/lib/__tests__/object.test.ts | 18 ++--- deno/lib/__tests__/partials.test.ts | 2 +- deno/lib/__tests__/pipeline.test.ts | 4 +- deno/lib/__tests__/preprocess.test.ts | 15 ++-- deno/lib/__tests__/record.test.ts | 4 +- deno/lib/__tests__/refine.test.ts | 39 +++++----- deno/lib/__tests__/safeparse.test.ts | 13 ++-- deno/lib/__tests__/set.test.ts | 23 +++--- deno/lib/__tests__/string.test.ts | 50 ++++++------- deno/lib/__tests__/transformer.test.ts | 20 +++--- deno/lib/__tests__/tuple.test.ts | 2 +- deno/lib/__tests__/unions.test.ts | 16 +++-- deno/lib/types.ts | 23 ++---- src/__tests__/all-errors.test.ts | 4 +- src/__tests__/array.test.ts | 2 +- src/__tests__/async-parsing.test.ts | 90 ++++++++++++------------ src/__tests__/base.test.ts | 10 ++- src/__tests__/catch.test.ts | 78 ++++++++++---------- src/__tests__/custom.test.ts | 2 +- src/__tests__/enum.test.ts | 13 ++-- src/__tests__/error.test.ts | 48 ++++++------- src/__tests__/generics.test.ts | 2 +- src/__tests__/instanceof.test.ts | 2 +- src/__tests__/intersection.test.ts | 8 +-- src/__tests__/literal.test.ts | 2 +- src/__tests__/map.test.ts | 20 +++--- src/__tests__/object-in-es5-env.test.ts | 6 +- src/__tests__/object.test.ts | 18 ++--- src/__tests__/partials.test.ts | 2 +- src/__tests__/pipeline.test.ts | 4 +- src/__tests__/preprocess.test.ts | 15 ++-- src/__tests__/record.test.ts | 4 +- src/__tests__/refine.test.ts | 39 +++++----- src/__tests__/safeparse.test.ts | 13 ++-- src/__tests__/set.test.ts | 23 +++--- src/__tests__/string.test.ts | 50 ++++++------- src/__tests__/transformer.test.ts | 20 +++--- src/__tests__/tuple.test.ts | 2 +- src/__tests__/unions.test.ts | 16 +++-- src/types.ts | 23 ++---- 53 files changed, 533 insertions(+), 493 deletions(-) diff --git a/deno/lib/__tests__/all-errors.test.ts b/deno/lib/__tests__/all-errors.test.ts index 7e69248ab..ae2cc3920 100644 --- a/deno/lib/__tests__/all-errors.test.ts +++ b/deno/lib/__tests__/all-errors.test.ts @@ -60,7 +60,7 @@ test("form errors type inference", () => { }); test(".flatten() type assertion", () => { - const parsed = Test.safeParse({}) as z.SafeParseError; + const parsed = z.safeParse(Test, {}) as z.SafeParseError; const validFlattenedErrors: TestFlattenedErrors = parsed.error.flatten( () => ({ message: "", code: 0 }) ); @@ -82,7 +82,7 @@ test(".flatten() type assertion", () => { }); test(".formErrors type assertion", () => { - const parsed = Test.safeParse({}) as z.SafeParseError; + const parsed = z.safeParse(Test, {}) as z.SafeParseError; const validFormErrors: TestFormErrors = parsed.error.formErrors; // @ts-expect-error should fail assertion between `TestFlattenedErrors` and `.formErrors`. const invalidFlattenedErrors: TestFlattenedErrors = parsed.error.formErrors; diff --git a/deno/lib/__tests__/array.test.ts b/deno/lib/__tests__/array.test.ts index 8aed9d63f..f9e1358c4 100644 --- a/deno/lib/__tests__/array.test.ts +++ b/deno/lib/__tests__/array.test.ts @@ -56,7 +56,7 @@ test("continue parsing despite array size error", () => { people: z.string().array().min(2), }); - const result = schema.safeParse({ + const result = z.safeParse(schema, { people: [123], }); expect(result.success).toEqual(false); diff --git a/deno/lib/__tests__/async-parsing.test.ts b/deno/lib/__tests__/async-parsing.test.ts index 83b4d6242..49f17fe49 100644 --- a/deno/lib/__tests__/async-parsing.test.ts +++ b/deno/lib/__tests__/async-parsing.test.ts @@ -11,11 +11,11 @@ test("string async parse", async () => { const goodData = "XXX"; const badData = 12; - const goodResult = await stringSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(stringSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await stringSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(stringSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -26,11 +26,11 @@ test("number async parse", async () => { const goodData = 1234.2353; const badData = "1234"; - const goodResult = await numberSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(numberSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await numberSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(numberSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -41,11 +41,11 @@ test("bigInt async parse", async () => { const goodData = BigInt(145); const badData = 134; - const goodResult = await bigIntSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(bigIntSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await bigIntSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(bigIntSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -56,11 +56,11 @@ test("boolean async parse", async () => { const goodData = true; const badData = 1; - const goodResult = await booleanSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(booleanSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await booleanSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(booleanSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -71,11 +71,11 @@ test("date async parse", async () => { const goodData = new Date(); const badData = new Date().toISOString(); - const goodResult = await dateSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(dateSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await dateSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(dateSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -86,11 +86,11 @@ test("undefined async parse", async () => { const goodData = undefined; const badData = "XXX"; - const goodResult = await undefinedSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(undefinedSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(undefined); - const badResult = await undefinedSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(undefinedSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -101,11 +101,11 @@ test("null async parse", async () => { const goodData = null; const badData = undefined; - const goodResult = await nullSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(nullSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await nullSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(nullSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -116,11 +116,11 @@ test("any async parse", async () => { const goodData = [{}]; // const badData = 'XXX'; - const goodResult = await anySchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(anySchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - // const badResult = await anySchema.safeParseAsync(badData); + // const badResult = await z.safeParseAsync(anySchema, badData); // expect(badResult.success).toBe(false); // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -131,11 +131,11 @@ test("unknown async parse", async () => { const goodData = ["asdf", 124, () => {}]; // const badData = 'XXX'; - const goodResult = await unknownSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(unknownSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - // const badResult = await unknownSchema.safeParseAsync(badData); + // const badResult = await z.safeParseAsync(unknownSchema, badData); // expect(badResult.success).toBe(false); // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -146,11 +146,11 @@ test("void async parse", async () => { const goodData = undefined; const badData = 0; - const goodResult = await voidSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(voidSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await voidSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(voidSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -161,11 +161,11 @@ test("array async parse", async () => { const goodData = ["XXX"]; const badData = "XXX"; - const goodResult = await arraySchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(arraySchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await arraySchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(arraySchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -176,11 +176,11 @@ test("object async parse", async () => { const goodData = { string: "XXX" }; const badData = { string: 12 }; - const goodResult = await objectSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(objectSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await objectSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(objectSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -191,11 +191,11 @@ test("union async parse", async () => { const goodData = undefined; const badData = null; - const goodResult = await unionSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(unionSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await unionSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(unionSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -206,11 +206,11 @@ test("record async parse", async () => { const goodData = { adsf: {}, asdf: {} }; const badData = [{}]; - const goodResult = await recordSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(recordSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await recordSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(recordSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -221,11 +221,11 @@ test("function async parse", async () => { const goodData = () => {}; const badData = "XXX"; - const goodResult = await functionSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(functionSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(typeof goodResult.data).toEqual("function"); - const badResult = await functionSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(functionSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -236,11 +236,11 @@ test("literal async parse", async () => { const goodData = "asdf"; const badData = "asdff"; - const goodResult = await literalSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(literalSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await literalSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(literalSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -251,11 +251,11 @@ test("enum async parse", async () => { const goodData = "whale"; const badData = "leopard"; - const goodResult = await enumSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(enumSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await enumSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(enumSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -270,11 +270,11 @@ test("nativeEnum async parse", async () => { const goodData = nativeEnumTest.asdf; const badData = "asdf"; - const goodResult = await nativeEnumSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(nativeEnumSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await nativeEnumSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(nativeEnumSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -284,7 +284,7 @@ const promiseSchema = z.promise(z.number()); test("promise async parse good", async () => { const goodData = Promise.resolve(123); - const goodResult = await promiseSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(promiseSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) { expect(goodResult.data).toBeInstanceOf(Promise); @@ -299,7 +299,7 @@ test("promise async parse good", async () => { test("promise async parse bad", async () => { const badData = Promise.resolve("XXX"); - const badResult = await promiseSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(promiseSchema, badData); expect(badResult.success).toBe(true); if (badResult.success) { await expect(badResult.data).rejects.toBeInstanceOf(z.ZodError); @@ -315,8 +315,8 @@ test("async validation non-empty strings", async () => { }); const testval = { hello: "", foo: "" }; - const result1 = base.safeParse(testval); - const result2 = base.safeParseAsync(testval); + const result1 = z.safeParse(base, testval); + const result2 = z.safeParseAsync(base, testval); const r1 = result1; await result2.then((r2) => { @@ -332,8 +332,8 @@ test("async validation multiple errors 1", async () => { }); const testval = { hello: 3, foo: "hello" }; - const result1 = base.safeParse(testval); - const result2 = base.safeParseAsync(testval); + const result1 = z.safeParse(base, testval); + const result2 = z.safeParseAsync(base, testval); const r1 = result1; await result2.then((r2) => { @@ -352,8 +352,8 @@ test("async validation multiple errors 2", async () => { }); const testval = { hello: 3, foo: { bar: 4 } }; - const result1 = base().safeParse(testval); - const result2 = base(true).safeParseAsync(testval); + const result1 = z.safeParse(base(), testval); + const result2 = z.safeParseAsync(base(true), testval); const r1 = result1; await result2.then((r2) => { @@ -379,7 +379,7 @@ test("ensure early async failure prevents follow-up refinement checks", async () }); const testval = { hello: "bye", foo: 3 }; - const result = await base.safeParseAsync(testval); + const result = await z.safeParseAsync(base, testval); if (result.success === false) { expect(result.error.issues.length).toBe(1); expect(count).toBe(1); diff --git a/deno/lib/__tests__/base.test.ts b/deno/lib/__tests__/base.test.ts index beda584d7..547d14a44 100644 --- a/deno/lib/__tests__/base.test.ts +++ b/deno/lib/__tests__/base.test.ts @@ -14,7 +14,7 @@ test("type guard", () => { type t1 = z.input; const data = { stringToNumber: "asdf" }; - const parsed = s1.safeParse(data); + const parsed = z.safeParse(s1, data); if (parsed.success) { util.assertEqual(true); } @@ -25,6 +25,10 @@ test("test this binding", () => { return predicate("hello"); }; - expect(callback((value) => z.string().safeParse(value).success)).toBe(true); // true - expect(callback((value) => z.string().safeParse(value).success)).toBe(true); // true + expect(callback((value) => z.safeParse(z.string(), value).success)).toBe( + true + ); // true + expect(callback((value) => z.safeParse(z.string(), value).success)).toBe( + true + ); // true }); diff --git a/deno/lib/__tests__/catch.test.ts b/deno/lib/__tests__/catch.test.ts index f8ea89911..b891b4c63 100644 --- a/deno/lib/__tests__/catch.test.ts +++ b/deno/lib/__tests__/catch.test.ts @@ -6,7 +6,7 @@ import { z } from "../index.ts"; import { util } from "../helpers/util.ts"; test("basic catch", () => { - expect(z.string().catch("default").parse(undefined)).toBe("default"); + expect(z.catch_(z.string(), "default").parse(undefined)).toBe("default"); }); test("catch fn does not run when parsing succeeds", () => { @@ -15,30 +15,30 @@ test("catch fn does not run when parsing succeeds", () => { isCalled = true; return "asdf"; }; - expect(z.string().catch(cb).parse("test")).toBe("test"); + expect(z.catch_(z.string(), cb).parse("test")).toBe("test"); expect(isCalled).toEqual(false); }); test("basic catch async", async () => { - const result = await z.string().catch("default").parseAsync(1243); + const result = await z.catch_(z.string(), "default").parseAsync(1243); expect(result).toBe("default"); }); test("catch replace wrong types", () => { - expect(z.string().catch("default").parse(true)).toBe("default"); - expect(z.string().catch("default").parse(true)).toBe("default"); - expect(z.string().catch("default").parse(15)).toBe("default"); - expect(z.string().catch("default").parse([])).toBe("default"); - expect(z.string().catch("default").parse(new Map())).toBe("default"); - expect(z.string().catch("default").parse(new Set())).toBe("default"); - expect(z.string().catch("default").parse({})).toBe("default"); + expect(z.catch_(z.string(), "default").parse(true)).toBe("default"); + expect(z.catch_(z.string(), "default").parse(true)).toBe("default"); + expect(z.catch_(z.string(), "default").parse(15)).toBe("default"); + expect(z.catch_(z.string(), "default").parse([])).toBe("default"); + expect(z.catch_(z.string(), "default").parse(new Map())).toBe("default"); + expect(z.catch_(z.string(), "default").parse(new Set())).toBe("default"); + expect(z.catch_(z.string(), "default").parse({})).toBe("default"); }); test("catch with transform", () => { - const stringWithDefault = z - .string() - .transform((val) => val.toUpperCase()) - .catch("default"); + const stringWithDefault = z.catch_( + z.string().transform((val) => val.toUpperCase()), + "default" + ); expect(stringWithDefault.parse(undefined)).toBe("default"); expect(stringWithDefault.parse(15)).toBe("default"); expect(stringWithDefault).toBeInstanceOf(z.ZodCatch); @@ -54,7 +54,7 @@ test("catch with transform", () => { }); test("catch on existing optional", () => { - const stringWithDefault = z.string().optional().catch("asdf"); + const stringWithDefault = z.catch_(z.string().optional(), "asdf"); expect(stringWithDefault.parse(undefined)).toBe(undefined); expect(stringWithDefault.parse(15)).toBe("asdf"); expect(stringWithDefault).toBeInstanceOf(z.ZodCatch); @@ -70,7 +70,7 @@ test("catch on existing optional", () => { }); test("optional on catch", () => { - const stringWithDefault = z.string().catch("asdf").optional(); + const stringWithDefault = z.catch_(z.string(), "asdf").optional(); type inp = z.input; util.assertEqual(true); @@ -79,15 +79,19 @@ test("optional on catch", () => { }); test("complex chain example", () => { - const complex = z - .string() - .catch("asdf") - .transform((val) => val + "!") - .transform((val) => val.toUpperCase()) - .catch("qwer") - .removeCatch() - .optional() - .catch("asdfasdf"); + const complex = z.catch_( + z + .catch_( + z + .catch_(z.string(), "asdf") + .transform((val) => val + "!") + .transform((val) => val.toUpperCase()), + "qwer" + ) + .removeCatch() + .optional(), + "asdfasdf" + ); expect(complex.parse("qwer")).toBe("QWER!"); expect(complex.parse(15)).toBe("ASDF!"); @@ -95,15 +99,15 @@ test("complex chain example", () => { }); test("removeCatch", () => { - const stringWithRemovedDefault = z.string().catch("asdf").removeCatch(); + const stringWithRemovedDefault = z.catch_(z.string(), "asdf").removeCatch(); type out = z.output; util.assertEqual(true); }); test("nested", () => { - const inner = z.string().catch("asdf"); - const outer = z.object({ inner }).catch({ + const inner = z.catch_(z.string(), "asdf"); + const outer = z.catch_(z.object({ inner }), { inner: "asdf", }); type input = z.input; @@ -116,7 +120,7 @@ test("nested", () => { }); test("chained catch", () => { - const stringWithDefault = z.string().catch("inner").catch("outer"); + const stringWithDefault = z.catch_(z.catch_(z.string(), "inner"), "outer"); const result = stringWithDefault.parse(undefined); expect(result).toEqual("inner"); const resultDiff = stringWithDefault.parse(5); @@ -136,7 +140,7 @@ test("native enum", () => { } const schema = z.object({ - fruit: z.nativeEnum(Fruits).catch(Fruits.apple), + fruit: z.catch_(z.nativeEnum(Fruits), Fruits.apple), }); expect(schema.parse({})).toEqual({ fruit: Fruits.apple }); @@ -145,7 +149,7 @@ test("native enum", () => { test("enum", () => { const schema = z.object({ - fruit: z.enum(["apple", "orange"]).catch("apple"), + fruit: z.catch_(z.enum(["apple", "orange"]), "apple"), }); expect(schema.parse({})).toEqual({ fruit: "apple" }); @@ -159,11 +163,11 @@ test("reported issues with nested usage", () => { obj: z.object({ sub: z.object({ lit: z.literal("a"), - subCatch: z.number().catch(23), + subCatch: z.catch_(z.number(), 23), }), - midCatch: z.number().catch(42), + midCatch: z.catch_(z.number(), 42), }), - number: z.number().catch(0), + number: z.catch_(z.number(), 0), bool: z.boolean(), }); @@ -195,14 +199,14 @@ test("catch error", () => { const schema = z.object({ age: z.number(), - name: z.string().catch((ctx) => { + name: z.catch_(z.string(), (ctx) => { catchError = ctx.error; return "John Doe"; }), }); - const result = schema.safeParse({ + const result = z.safeParse(schema, { age: null, name: null, }); @@ -221,7 +225,7 @@ test("catch error", () => { }); test("ctx.input", () => { - const schema = z.string().catch((ctx) => { + const schema = z.catch_(z.string(), (ctx) => { return String(ctx.input); }); diff --git a/deno/lib/__tests__/custom.test.ts b/deno/lib/__tests__/custom.test.ts index a19233ecf..be6130419 100644 --- a/deno/lib/__tests__/custom.test.ts +++ b/deno/lib/__tests__/custom.test.ts @@ -12,7 +12,7 @@ test("passing validations", () => { test("string params", () => { const example1 = z.custom((x) => typeof x !== "number", "customerr"); - const result = example1.safeParse(1234); + const result = z.safeParse(example1, 1234); expect(result.success).toEqual(false); // @ts-ignore expect(JSON.stringify(result.error).includes("customerr")).toEqual(true); diff --git a/deno/lib/__tests__/enum.test.ts b/deno/lib/__tests__/enum.test.ts index af3bcc9ad..dce882394 100644 --- a/deno/lib/__tests__/enum.test.ts +++ b/deno/lib/__tests__/enum.test.ts @@ -33,9 +33,10 @@ test("readonly enum", () => { }); test("error params", () => { - const result = z - .enum(["test"], { required_error: "REQUIRED" }) - .safeParse(undefined); + const result = z.safeParse( + z.enum(["test"], { required_error: "REQUIRED" }), + undefined + ); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("REQUIRED"); @@ -65,8 +66,8 @@ test("error map in extract/exclude", () => { errorMap: () => ({ message: "This is not food!" }), }); const ItalianEnum = FoodEnum.extract(["Pasta", "Pizza"]); - const foodsError = FoodEnum.safeParse("Cucumbers"); - const italianError = ItalianEnum.safeParse("Tacos"); + const foodsError = z.safeParse(FoodEnum, "Cucumbers"); + const italianError = z.safeParse(ItalianEnum, "Tacos"); if (!foodsError.success && !italianError.success) { expect(foodsError.error.issues[0].message).toEqual( italianError.error.issues[0].message @@ -76,7 +77,7 @@ test("error map in extract/exclude", () => { const UnhealthyEnum = FoodEnum.exclude(["Salad"], { errorMap: () => ({ message: "This is not healthy food!" }), }); - const unhealthyError = UnhealthyEnum.safeParse("Salad"); + const unhealthyError = z.safeParse(UnhealthyEnum, "Salad"); if (!unhealthyError.success) { expect(unhealthyError.error.issues[0].message).toEqual( "This is not healthy food!" diff --git a/deno/lib/__tests__/error.test.ts b/deno/lib/__tests__/error.test.ts index e66b185eb..cfee717b0 100644 --- a/deno/lib/__tests__/error.test.ts +++ b/deno/lib/__tests__/error.test.ts @@ -165,7 +165,7 @@ test("custom path in custom error map", () => { expect(error.path.length).toBe(2); return { message: "doesnt matter" }; }; - const result = schema.safeParse({ items: ["first"] }, { errorMap }); + const result = z.safeParse(schema, { items: ["first"] }, { errorMap }); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].path).toEqual(["items", "items-too-few"]); @@ -178,7 +178,7 @@ test("error metadata from value", () => { (val) => ({ params: { val } }) ); - const result = dynamicRefine.safeParse("asdf"); + const result = z.safeParse(dynamicRefine, "asdf"); expect(result.success).toEqual(false); if (!result.success) { const sub = result.error.issues[0]; @@ -199,12 +199,12 @@ test("error metadata from value", () => { // ]) // .refine((v) => v >= 1); -// expect(() => asdf.safeParse("foo")).not.toThrow(); +// expect(() => z.safeParse(asdf, "foo")).not.toThrow(); // }); test("root level formatting", () => { const schema = z.string().email(); - const result = schema.safeParse("asdfsdf"); + const result = z.safeParse(schema, "asdfsdf"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.format()._errors).toEqual(["Invalid email"]); @@ -219,7 +219,7 @@ test("custom path", () => { }) .refine((val) => val.confirm === val.password, { path: ["confirm"] }); - const result = schema.safeParse({ + const result = z.safeParse(schema, { password: "peanuts", confirm: "qeanuts", }); @@ -242,7 +242,7 @@ test("custom path", () => { }) .refine((val) => val.confirm === val.password); - const result = schema.safeParse({ + const result = z.safeParse(schema, { password: "qwer", confirm: "asdf", }); @@ -268,7 +268,7 @@ test("no abort early on refinements", () => { inner: { name: ["aasd", "asdfasdfasfd"] }, }; - const result1 = schema.safeParse(invalidItem); + const result1 = z.safeParse(schema, invalidItem); expect(result1.success).toEqual(false); if (!result1.success) { expect(result1.error.issues.length).toEqual(2); @@ -281,8 +281,8 @@ test("formatting", () => { const invalidArray = { inner: { name: ["asdfasdf", "asdfasdfasfd"] }, }; - const result1 = schema.safeParse(invalidItem); - const result2 = schema.safeParse(invalidArray); + const result1 = z.safeParse(schema, invalidItem); + const result2 = z.safeParse(schema, invalidArray); expect(result1.success).toEqual(false); expect(result2.success).toEqual(false); @@ -334,7 +334,7 @@ test("formatting with nullable and optional fields", () => { optionalArray: ["abcd"], optionalTuple: ["abcd", "abcd", 1], }; - const result = schema.safeParse(invalidItem); + const result = z.safeParse(schema, invalidItem); expect(result.success).toEqual(false); if (!result.success) { type FormattedError = z.inferFormattedError; @@ -369,20 +369,20 @@ const stringWithCustomError = z.string({ }); test("schema-bound error map", () => { - const result = stringWithCustomError.safeParse(1234); + const result = z.safeParse(stringWithCustomError, 1234); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("Invalid name"); } - const result2 = stringWithCustomError.safeParse(undefined); + const result2 = z.safeParse(stringWithCustomError, undefined); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].message).toEqual("Name is required"); } // support contextual override - const result3 = stringWithCustomError.safeParse(undefined, { + const result3 = z.safeParse(stringWithCustomError, undefined, { errorMap: () => ({ message: "OVERRIDE" }), }); expect(result3.success).toEqual(false); @@ -394,7 +394,7 @@ test("schema-bound error map", () => { test("overrideErrorMap", () => { // support overrideErrorMap z.setErrorMap(() => ({ message: "OVERRIDE" })); - const result4 = stringWithCustomError.min(10).safeParse("tooshort"); + const result4 = z.safeParse(stringWithCustomError.min(10), "tooshort"); expect(result4.success).toEqual(false); if (!result4.success) { expect(result4.error.issues[0].message).toEqual("OVERRIDE"); @@ -407,12 +407,12 @@ test("invalid and required", () => { invalid_type_error: "Invalid name", required_error: "Name is required", }); - const result1 = str.safeParse(1234); + const result1 = z.safeParse(str, 1234); expect(result1.success).toEqual(false); if (!result1.success) { expect(result1.error.issues[0].message).toEqual("Invalid name"); } - const result2 = str.safeParse(undefined); + const result2 = z.safeParse(str, undefined); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].message).toEqual("Name is required"); @@ -425,7 +425,7 @@ test("Fallback to default required error", () => { // required_error: "Name is required", }); - const result2 = str.safeParse(undefined); + const result2 = z.safeParse(str, undefined); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].message).toEqual("Required"); @@ -445,7 +445,7 @@ test("invalid and required and errorMap", () => { test("strict error message", () => { const errorMsg = "Invalid object"; const obj = z.object({ x: z.string() }).strict(errorMsg); - const result = obj.safeParse({ x: "a", y: "b" }); + const result = z.safeParse(obj, { x: "a", y: "b" }); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual(errorMsg); @@ -521,7 +521,7 @@ test("enum with message returns the custom error message", () => { message: "the value provided is invalid", }); - const result1 = schema.safeParse("berries"); + const result1 = z.safeParse(schema, "berries"); expect(result1.success).toEqual(false); if (!result1.success) { expect(result1.error.issues[0].message).toEqual( @@ -529,7 +529,7 @@ test("enum with message returns the custom error message", () => { ); } - const result2 = schema.safeParse(undefined); + const result2 = z.safeParse(schema, undefined); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].message).toEqual( @@ -537,10 +537,10 @@ test("enum with message returns the custom error message", () => { ); } - const result3 = schema.safeParse("banana"); + const result3 = z.safeParse(schema, "banana"); expect(result3.success).toEqual(true); - const result4 = schema.safeParse(null); + const result4 = z.safeParse(schema, null); expect(result4.success).toEqual(false); if (!result4.success) { expect(result4.error.issues[0].message).toEqual( @@ -551,7 +551,7 @@ test("enum with message returns the custom error message", () => { test("when the message is falsy, it is used as is provided", () => { const schema = z.string().max(1, { message: "" }); - const result = schema.safeParse("asdf"); + const result = z.safeParse(schema, "asdf"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual(""); @@ -568,7 +568,7 @@ test("when the message is falsy, it is used as is provided", () => { // message: "Passwords don't match", // path: ["confirm"], // }); -// const result = user.safeParse({ password: "asdf", confirm: "qwer" }); +// const result = z.safeParse(user, { password: "asdf", confirm: "qwer" }); // if (!result.success) { // expect(result.error.issues.length).toEqual(2); // } diff --git a/deno/lib/__tests__/generics.test.ts b/deno/lib/__tests__/generics.test.ts index 4b0763fe5..7e5510a89 100644 --- a/deno/lib/__tests__/generics.test.ts +++ b/deno/lib/__tests__/generics.test.ts @@ -48,5 +48,5 @@ test("nested no undefined", () => { const outer = z.object({ inner }); type outerSchema = z.infer; z.util.assertEqual(true); - expect(outer.safeParse({ inner: undefined }).success).toEqual(false); + expect(z.safeParse(outer, { inner: undefined }).success).toEqual(false); }); diff --git a/deno/lib/__tests__/instanceof.test.ts b/deno/lib/__tests__/instanceof.test.ts index 2f1f9187c..52f1dc70a 100644 --- a/deno/lib/__tests__/instanceof.test.ts +++ b/deno/lib/__tests__/instanceof.test.ts @@ -37,6 +37,6 @@ test("instanceof", async () => { test("instanceof fatal", () => { const schema = z.instanceof(Date).refine((d) => d.toString()); - const res = schema.safeParse(null); + const res = z.safeParse(schema, null); expect(res.success).toBe(false); }); diff --git a/deno/lib/__tests__/intersection.test.ts b/deno/lib/__tests__/intersection.test.ts index 9e647ffa0..10ae3599d 100644 --- a/deno/lib/__tests__/intersection.test.ts +++ b/deno/lib/__tests__/intersection.test.ts @@ -78,7 +78,7 @@ test("invalid intersection types", async () => { z.number().transform((x) => x + 1) ); - const syncResult = numberIntersection.safeParse(1234); + const syncResult = z.safeParse(numberIntersection, 1234); expect(syncResult.success).toEqual(false); if (!syncResult.success) { expect(syncResult.error.issues[0].code).toEqual( @@ -86,7 +86,7 @@ test("invalid intersection types", async () => { ); } - const asyncResult = await numberIntersection.spa(1234); + const asyncResult = await z.spa(numberIntersection, 1234); expect(asyncResult.success).toEqual(false); if (!asyncResult.success) { expect(asyncResult.error.issues[0].code).toEqual( @@ -103,7 +103,7 @@ test("invalid array merge", async () => { .array() .transform((val) => [...val, "asdf"]) ); - const syncResult = stringArrInt.safeParse(["asdf", "qwer"]); + const syncResult = z.safeParse(stringArrInt, ["asdf", "qwer"]); expect(syncResult.success).toEqual(false); if (!syncResult.success) { expect(syncResult.error.issues[0].code).toEqual( @@ -111,7 +111,7 @@ test("invalid array merge", async () => { ); } - const asyncResult = await stringArrInt.spa(["asdf", "qwer"]); + const asyncResult = await z.spa(stringArrInt, ["asdf", "qwer"]); expect(asyncResult.success).toEqual(false); if (!asyncResult.success) { expect(asyncResult.error.issues[0].code).toEqual( diff --git a/deno/lib/__tests__/literal.test.ts b/deno/lib/__tests__/literal.test.ts index b3f074162..f88d4e14a 100644 --- a/deno/lib/__tests__/literal.test.ts +++ b/deno/lib/__tests__/literal.test.ts @@ -27,7 +27,7 @@ test("failing validations", () => { test("invalid_literal should have `received` field with data", () => { const data = "shark"; - const result = literalTuna.safeParse(data); + const result = z.safeParse(literalTuna, data); if (!result.success) { const issue = result.error.issues[0]; if (issue.code === "invalid_literal") { diff --git a/deno/lib/__tests__/map.test.ts b/deno/lib/__tests__/map.test.ts index 9a2a6d783..cfbf425f8 100644 --- a/deno/lib/__tests__/map.test.ts +++ b/deno/lib/__tests__/map.test.ts @@ -14,7 +14,8 @@ test("type inference", () => { }); test("valid parse", () => { - const result = stringMap.safeParse( + const result = z.safeParse( + stringMap, new Map([ ["first", "foo"], ["second", "bar"], @@ -30,7 +31,8 @@ test("valid parse", () => { }); test("valid parse async", async () => { - const result = await stringMap.spa( + const result = await z.spa( + stringMap, new Map([ ["first", "foo"], ["second", "bar"], @@ -46,7 +48,7 @@ test("valid parse async", async () => { }); test("throws when a Set is given", () => { - const result = stringMap.safeParse(new Set([])); + const result = z.safeParse(stringMap, new Set([])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(1); @@ -55,7 +57,7 @@ test("throws when a Set is given", () => { }); test("throws when the given map has invalid key and invalid input", () => { - const result = stringMap.safeParse(new Map([[42, Symbol()]])); + const result = z.safeParse(stringMap, new Map([[42, Symbol()]])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(2); @@ -67,16 +69,17 @@ test("throws when the given map has invalid key and invalid input", () => { }); test("throws when the given map has multiple invalid entries", () => { - // const result = stringMap.safeParse(new Map([[42, Symbol()]])); + // const result = z.safeParse(stringMap, new Map([[42, Symbol()]])); - const result = stringMap.safeParse( + const result = z.safeParse( + stringMap, new Map([ [1, "foo"], ["bar", 2], ] as [any, any][]) as Map ); - // const result = stringMap.safeParse(new Map([[42, Symbol()]])); + // const result = z.safeParse(stringMap, new Map([[42, Symbol()]])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(2); @@ -94,7 +97,8 @@ test("dirty", async () => { }), z.string() ); - const result = await map.spa( + const result = await z.spa( + map, new Map([ ["first", "foo"], ["second", "bar"], diff --git a/deno/lib/__tests__/object.test.ts b/deno/lib/__tests__/object.test.ts index ff636a078..c9ebf7561 100644 --- a/deno/lib/__tests__/object.test.ts +++ b/deno/lib/__tests__/object.test.ts @@ -110,7 +110,7 @@ test("strip unknown", () => { }); test("strict", () => { - const val = z.object({ points: z.number() }).strict().safeParse(data); + const val = z.safeParse(z.object({ points: z.number() }).strict(), data); expect(val.success).toEqual(false); }); @@ -185,10 +185,10 @@ test("test catchall parsing", async () => { expect(result).toEqual({ name: "Foo", validExtraKey: 61 }); - const result2 = z - .object({ name: z.string() }) - .catchall(z.number()) - .safeParse({ name: "Foo", validExtraKey: 61, invalid: "asdf" }); + const result2 = z.safeParse( + z.object({ name: z.string() }).catchall(z.number()), + { name: "Foo", validExtraKey: 61, invalid: "asdf" } + ); expect(result2.success).toEqual(false); }); @@ -199,7 +199,7 @@ test("test nonexistent keys", async () => { z.object({ b: z.number() }), ]); const obj = { a: "A" }; - const result = await Schema.spa(obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 + const result = await z.spa(Schema, obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 expect(result.success).toBe(true); }); @@ -214,7 +214,7 @@ test("test async union", async () => { ]); const obj = { ty: "A" }; - const result = await Schema2.spa(obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 + const result = await z.spa(Schema2, obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 expect(result.success).toEqual(true); }); @@ -311,10 +311,10 @@ test("strictcreate", async () => { name: z.string(), }); - const syncResult = strictObj.safeParse({ name: "asdf", unexpected: 13 }); + const syncResult = z.safeParse(strictObj, { name: "asdf", unexpected: 13 }); expect(syncResult.success).toEqual(false); - const asyncResult = await strictObj.spa({ name: "asdf", unexpected: 13 }); + const asyncResult = await z.spa(strictObj, { name: "asdf", unexpected: 13 }); expect(asyncResult.success).toEqual(false); }); diff --git a/deno/lib/__tests__/partials.test.ts b/deno/lib/__tests__/partials.test.ts index 1825753a9..239703ef3 100644 --- a/deno/lib/__tests__/partials.test.ts +++ b/deno/lib/__tests__/partials.test.ts @@ -249,5 +249,5 @@ test("deeppartial array", () => { schema.parse({}); // should be false, but is true - expect(schema.safeParse({ array: [] }).success).toBe(false); + expect(z.safeParse(schema, { array: [] }).success).toBe(false); }); diff --git a/deno/lib/__tests__/pipeline.test.ts b/deno/lib/__tests__/pipeline.test.ts index 349505a2c..0937175e1 100644 --- a/deno/lib/__tests__/pipeline.test.ts +++ b/deno/lib/__tests__/pipeline.test.ts @@ -23,8 +23,8 @@ test("break if dirty", () => { .refine((c) => c === "1234") .transform(async (val) => Number(val)) .pipe(z.number().refine((v) => v < 100)); - const r1: any = schema.safeParse("12345"); + const r1: any = z.safeParse(schema, "12345"); expect(r1.error.issues.length).toBe(1); - const r2: any = schema.safeParse("3"); + const r2: any = z.safeParse(schema, "3"); expect(r2.error.issues.length).toBe(1); }); diff --git a/deno/lib/__tests__/preprocess.test.ts b/deno/lib/__tests__/preprocess.test.ts index 50ac02e05..3d99eaedb 100644 --- a/deno/lib/__tests__/preprocess.test.ts +++ b/deno/lib/__tests__/preprocess.test.ts @@ -10,7 +10,7 @@ test("preprocess", () => { const value = schema.parse("asdf"); expect(value).toEqual(["asdf"]); - util.assertEqual<(typeof schema)["_input"], unknown>(true); + util.assertEqual, unknown>(true); }); test("async preprocess", async () => { @@ -100,15 +100,16 @@ test("async preprocess ctx.addIssue with parse", async () => { }); test("preprocess ctx.addIssue with parseAsync", async () => { - const result = await z - .preprocess(async (data, ctx) => { + const result = await z.safeParseAsync( + z.preprocess(async (data, ctx) => { ctx.addIssue({ code: "custom", message: `${data} is not one of our allowed strings`, }); return data; - }, z.string()) - .safeParseAsync("asdf"); + }, z.string()), + "asdf" + ); expect(JSON.parse(JSON.stringify(result))).toEqual({ success: false, @@ -136,7 +137,7 @@ test("z.NEVER in preprocess", () => { type foo = z.infer; util.assertEqual(true); - const arg = foo.safeParse(undefined); + const arg = z.safeParse(foo, undefined); if (!arg.success) { expect(arg.error.issues[0].message).toEqual("bad"); } @@ -146,7 +147,7 @@ test("preprocess as the second property of object", () => { nonEmptyStr: z.string().min(1), positiveNum: z.preprocess((v) => Number(v), z.number().positive()), }); - const result = schema.safeParse({ + const result = z.safeParse(schema, { nonEmptyStr: "", positiveNum: "", }); diff --git a/deno/lib/__tests__/record.test.ts b/deno/lib/__tests__/record.test.ts index 311f805a7..1eea1902f 100644 --- a/deno/lib/__tests__/record.test.ts +++ b/deno/lib/__tests__/record.test.ts @@ -156,7 +156,7 @@ test("is not vulnerable to prototype pollution", async () => { const obj1 = rec.parse(data); expect(obj1.a).toBeUndefined(); - const obj2 = rec.safeParse(data); + const obj2 = z.safeParse(rec, data); expect(obj2.success).toBe(true); if (obj2.success) { expect(obj2.data.a).toBeUndefined(); @@ -165,7 +165,7 @@ test("is not vulnerable to prototype pollution", async () => { const obj3 = await rec.parseAsync(data); expect(obj3.a).toBeUndefined(); - const obj4 = await rec.safeParseAsync(data); + const obj4 = await z.safeParseAsync(rec, data); expect(obj4.success).toBe(true); if (obj4.success) { expect(obj4.data.a).toBeUndefined(); diff --git a/deno/lib/__tests__/refine.test.ts b/deno/lib/__tests__/refine.test.ts index f505fdbb7..b11f61d22 100644 --- a/deno/lib/__tests__/refine.test.ts +++ b/deno/lib/__tests__/refine.test.ts @@ -85,13 +85,15 @@ test("refinement Promise", async () => { }); test("custom path", async () => { - const result = await z - .object({ - password: z.string(), - confirm: z.string(), - }) - .refine((data) => data.confirm === data.password, { path: ["confirm"] }) - .spa({ password: "asdf", confirm: "qewr" }); + const result = await z.spa( + z + .object({ + password: z.string(), + confirm: z.string(), + }) + .refine((data) => data.confirm === data.password, { path: ["confirm"] }), + { password: "asdf", confirm: "qewr" } + ); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].path).toEqual(["confirm"]); @@ -115,8 +117,8 @@ test("use path in refinement context", async () => { foo: noNested, }); - const t1 = await noNested.spa("asdf"); - const t2 = await data.spa({ foo: "asdf" }); + const t1 = await z.spa(noNested, "asdf"); + const t2 = await z.spa(data, { foo: "asdf" }); expect(t1.success).toBe(true); expect(t2.success).toBe(false); @@ -148,7 +150,7 @@ test("superRefine", () => { } }); - const result = Strings.safeParse(["asfd", "asfd", "asfd", "asfd"]); + const result = z.safeParse(Strings, ["asfd", "asfd", "asfd", "asfd"]); expect(result.success).toEqual(false); if (!result.success) expect(result.error.issues.length).toEqual(2); @@ -177,7 +179,12 @@ test("superRefine async", async () => { } }); - const result = await Strings.safeParseAsync(["asfd", "asfd", "asfd", "asfd"]); + const result = await z.safeParseAsync(Strings, [ + "asfd", + "asfd", + "asfd", + "asfd", + ]); expect(result.success).toEqual(false); if (!result.success) expect(result.error.issues.length).toEqual(2); @@ -208,8 +215,8 @@ test("superRefine - type narrowing", () => { util.assertEqual, NarrowType>(true); - expect(schema.safeParse({ type: "test", age: 0 }).success).toEqual(true); - expect(schema.safeParse(null).success).toEqual(false); + expect(z.safeParse(schema, { type: "test", age: 0 }).success).toEqual(true); + expect(z.safeParse(schema, null).success).toEqual(false); }); test("chained mixed refining types", () => { @@ -264,14 +271,14 @@ test("chained refinements", () => { path: ["size"], message: "size greater than 7", }); - const r1 = objectSchema.safeParse({ + const r1 = z.safeParse(objectSchema, { length: 4, size: 9, }); expect(r1.success).toEqual(false); if (!r1.success) expect(r1.error.issues.length).toEqual(1); - const r2 = objectSchema.safeParse({ + const r2 = z.safeParse(objectSchema, { length: 4, size: 3, }); @@ -300,7 +307,7 @@ test("fatal superRefine", () => { } }); - const result = Strings.safeParse(""); + const result = z.safeParse(Strings, ""); expect(result.success).toEqual(false); if (!result.success) expect(result.error.issues.length).toEqual(1); diff --git a/deno/lib/__tests__/safeparse.test.ts b/deno/lib/__tests__/safeparse.test.ts index fbae3d72b..1762437c1 100644 --- a/deno/lib/__tests__/safeparse.test.ts +++ b/deno/lib/__tests__/safeparse.test.ts @@ -6,23 +6,24 @@ import * as z from "../index.ts"; const stringSchema = z.string(); test("safeparse fail", () => { - const safe = stringSchema.safeParse(12); + const safe = z.safeParse(stringSchema, 12); expect(safe.success).toEqual(false); expect(safe.error).toBeInstanceOf(z.ZodError); }); test("safeparse pass", () => { - const safe = stringSchema.safeParse("12"); + const safe = z.safeParse(stringSchema, "12"); expect(safe.success).toEqual(true); expect(safe.data).toEqual("12"); }); test("safeparse unexpected error", () => { expect(() => - stringSchema - .refine((data) => { + z.safeParse( + stringSchema.refine((data) => { throw new Error(data); - }) - .safeParse("12") + }), + "12" + ) ).toThrow(); }); diff --git a/deno/lib/__tests__/set.test.ts b/deno/lib/__tests__/set.test.ts index 0626bac94..5e0a1b605 100644 --- a/deno/lib/__tests__/set.test.ts +++ b/deno/lib/__tests__/set.test.ts @@ -20,7 +20,7 @@ test("type inference", () => { }); test("valid parse", () => { - const result = stringSet.safeParse(new Set(["first", "second"])); + const result = z.safeParse(stringSet, new Set(["first", "second"])); expect(result.success).toEqual(true); if (result.success) { expect(result.data.has("first")).toEqual(true); @@ -40,7 +40,7 @@ test("valid parse", () => { }); test("valid parse async", async () => { - const result = await stringSet.spa(new Set(["first", "second"])); + const result = await z.spa(stringSet, new Set(["first", "second"])); expect(result.success).toEqual(true); if (result.success) { expect(result.data.has("first")).toEqual(true); @@ -48,7 +48,10 @@ test("valid parse async", async () => { expect(result.data.has("third")).toEqual(false); } - const asyncResult = await stringSet.safeParse(new Set(["first", "second"])); + const asyncResult = await z.safeParse( + stringSet, + new Set(["first", "second"]) + ); expect(asyncResult.success).toEqual(true); if (asyncResult.success) { expect(asyncResult.data.has("first")).toEqual(true); @@ -76,7 +79,7 @@ test("valid parse: size-related methods", () => { }); test("failing when parsing empty set in nonempty ", () => { - const result = nonEmpty.safeParse(new Set()); + const result = z.safeParse(nonEmpty, new Set()); expect(result.success).toEqual(false); if (result.success === false) { @@ -86,7 +89,7 @@ test("failing when parsing empty set in nonempty ", () => { }); test("failing when set is smaller than min() ", () => { - const result = minTwo.safeParse(new Set(["just_one"])); + const result = z.safeParse(minTwo, new Set(["just_one"])); expect(result.success).toEqual(false); if (result.success === false) { @@ -96,7 +99,7 @@ test("failing when set is smaller than min() ", () => { }); test("failing when set is bigger than max() ", () => { - const result = maxTwo.safeParse(new Set(["one", "two", "three"])); + const result = z.safeParse(maxTwo, new Set(["one", "two", "three"])); expect(result.success).toEqual(false); if (result.success === false) { @@ -106,12 +109,12 @@ test("failing when set is bigger than max() ", () => { }); test("doesn’t throw when an empty set is given", () => { - const result = stringSet.safeParse(new Set([])); + const result = z.safeParse(stringSet, new Set([])); expect(result.success).toEqual(true); }); test("throws when a Map is given", () => { - const result = stringSet.safeParse(new Map([])); + const result = z.safeParse(stringSet, new Map([])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(1); @@ -120,7 +123,7 @@ test("throws when a Map is given", () => { }); test("throws when the given set has invalid input", () => { - const result = stringSet.safeParse(new Set([Symbol()])); + const result = z.safeParse(stringSet, new Set([Symbol()])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(1); @@ -130,7 +133,7 @@ test("throws when the given set has invalid input", () => { }); test("throws when the given set has multiple invalid entries", () => { - const result = stringSet.safeParse(new Set([1, 2] as any[]) as Set); + const result = z.safeParse(stringSet, new Set([1, 2] as any[]) as Set); expect(result.success).toEqual(false); if (result.success === false) { diff --git a/deno/lib/__tests__/string.test.ts b/deno/lib/__tests__/string.test.ts index 3f5b95562..5d0c7ad8e 100644 --- a/deno/lib/__tests__/string.test.ts +++ b/deno/lib/__tests__/string.test.ts @@ -155,12 +155,12 @@ test("email validations", () => { expect( validEmails.every((email) => { - return emailSchema.safeParse(email).success; + return z.safeParse(emailSchema, email).success; }) ).toBe(true); expect( invalidEmails.every((email) => { - return emailSchema.safeParse(email).success === false; + return z.safeParse(emailSchema, email).success === false; }) ).toBe(true); }); @@ -180,7 +180,9 @@ test("base64 validations", () => { ]; for (const str of validBase64Strings) { - expect(str + z.string().base64().safeParse(str).success).toBe(str + "true"); + expect(str + z.safeParse(z.string().base64(), str).success).toBe( + str + "true" + ); } const invalidBase64Strings = [ @@ -194,7 +196,7 @@ test("base64 validations", () => { ]; for (const str of invalidBase64Strings) { - expect(str + z.string().base64().safeParse(str).success).toBe( + expect(str + z.safeParse(z.string().base64(), str).success).toBe( str + "false" ); } @@ -251,7 +253,7 @@ test("uuid", () => { uuid.parse("00000000-0000-0000-0000-000000000000"); uuid.parse("b3ce60f8-e8b9-40f5-1150-172ede56ff74"); // Variant 0 - RFC 4122: Reserved, NCS backward compatibility uuid.parse("92e76bf9-28b3-4730-cd7f-cb6bc51f8c09"); // Variant 2 - RFC 4122: Reserved, Microsoft Corporation backward compatibility - const result = uuid.safeParse("9491d710-3185-4e06-bea0-6a2f275345e0X"); + const result = z.safeParse(uuid, "9491d710-3185-4e06-bea0-6a2f275345e0X"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("custom error"); @@ -261,7 +263,7 @@ test("uuid", () => { test("bad uuid", () => { const uuid = z.string().uuid("custom error"); uuid.parse("9491d710-3185-4e06-bea0-6a2f275345e0"); - const result = uuid.safeParse("invalid uuid"); + const result = z.safeParse(uuid, "invalid uuid"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("custom error"); @@ -274,7 +276,7 @@ test("nanoid", () => { nanoid.parse("mIU_4PJWikaU8fMbmkouz"); nanoid.parse("Hb9ZUtUa2JDm_dD-47EGv"); nanoid.parse("5Noocgv_8vQ9oPijj4ioQ"); - const result = nanoid.safeParse("Xq90uDyhddC53KsoASYJGX"); + const result = z.safeParse(nanoid, "Xq90uDyhddC53KsoASYJGX"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("custom error"); @@ -284,7 +286,7 @@ test("nanoid", () => { test("bad nanoid", () => { const nanoid = z.string().nanoid("custom error"); nanoid.parse("ySh_984wpDUu7IQRrLXAp"); - const result = nanoid.safeParse("invalid nanoid"); + const result = z.safeParse(nanoid, "invalid nanoid"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("custom error"); @@ -294,7 +296,7 @@ test("bad nanoid", () => { test("cuid", () => { const cuid = z.string().cuid(); cuid.parse("ckopqwooh000001la8mbi2im9"); - const result = cuid.safeParse("cifjhdsfhsd-invalid-cuid"); + const result = z.safeParse(cuid, "cifjhdsfhsd-invalid-cuid"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("Invalid cuid"); @@ -314,7 +316,7 @@ test("cuid2", () => { "tz4a98xxat96iws9zMbrgj3a", // include uppercase "tz4a98xxat96iws-zmbrgj3a", // involve symbols ]; - const results = invalidStrings.map((s) => cuid2.safeParse(s)); + const results = invalidStrings.map((s) => z.safeParse(cuid2, s)); expect(results.every((r) => !r.success)).toEqual(true); if (!results[0].success) { expect(results[0].error.issues[0].message).toEqual("Invalid cuid2"); @@ -324,10 +326,10 @@ test("cuid2", () => { test("ulid", () => { const ulid = z.string().ulid(); ulid.parse("01ARZ3NDEKTSV4RRFFQ69G5FAV"); - const result = ulid.safeParse("invalidulid"); + const result = z.safeParse(ulid, "invalidulid"); expect(result.success).toEqual(false); const tooLong = "01ARZ3NDEKTSV4RRFFQ69G5FAVA"; - expect(ulid.safeParse(tooLong).success).toEqual(false); + expect(z.safeParse(ulid, tooLong).success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("Invalid ulid"); } @@ -341,10 +343,10 @@ test("regex", () => { }); test("regexp error message", () => { - const result = z + const result = z.safeParse(z .string() .regex(/^moo+$/) - .safeParse("boooo"); + ,"boooo") if (!result.success) { expect(result.error.issues[0].message).toEqual("Invalid"); } else { @@ -356,11 +358,11 @@ test("regexp error message", () => { test("regex lastIndex reset", () => { const schema = z.string().regex(/^\d+$/g); - expect(schema.safeParse("123").success).toEqual(true); - expect(schema.safeParse("123").success).toEqual(true); - expect(schema.safeParse("123").success).toEqual(true); - expect(schema.safeParse("123").success).toEqual(true); - expect(schema.safeParse("123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); }); test("checks getters", () => { @@ -708,14 +710,14 @@ test("duration", () => { ]; for (const val of validDurations) { - const result = duration.safeParse(val); + const result = z.safeParse(duration, val); if (!result.success) { throw Error(`Valid duration could not be parsed: ${val}`); } } for (const val of invalidDurations) { - const result = duration.safeParse(val); + const result = z.safeParse(duration, val); if (result.success) { throw Error(`Invalid duration was successful parsed: ${val}`); @@ -727,7 +729,7 @@ test("duration", () => { test("IP validation", () => { const ip = z.string().ip(); - expect(ip.safeParse("122.122.122.122").success).toBe(true); + expect(z.safeParse(ip, "122.122.122.122").success).toBe(true); const ipv4 = z.string().ip({ version: "v4" }); expect(() => ipv4.parse("6097:adfa:6f0b:220d:db08:5021:6191:7990")).toThrow(); @@ -760,8 +762,8 @@ test("IP validation", () => { ]; // no parameters check IPv4 or IPv6 const ipSchema = z.string().ip(); - expect(validIPs.every((ip) => ipSchema.safeParse(ip).success)).toBe(true); + expect(validIPs.every((ip) => z.safeParse(ipSchema, ip).success)).toBe(true); expect( - invalidIPs.every((ip) => ipSchema.safeParse(ip).success === false) + invalidIPs.every((ip) => z.safeParse(ipSchema, ip).success === false) ).toBe(true); }); diff --git a/deno/lib/__tests__/transformer.test.ts b/deno/lib/__tests__/transformer.test.ts index 108b12e91..db117ad0f 100644 --- a/deno/lib/__tests__/transformer.test.ts +++ b/deno/lib/__tests__/transformer.test.ts @@ -45,9 +45,8 @@ test("transform ctx.addIssue with parse", () => { test("transform ctx.addIssue with parseAsync", async () => { const strs = ["foo", "bar"]; - const result = await z - .string() - .transform(async (data, ctx) => { + const result = await z.safeParseAsync( + z.string().transform(async (data, ctx) => { const i = strs.indexOf(data); if (i === -1) { ctx.addIssue({ @@ -56,8 +55,9 @@ test("transform ctx.addIssue with parseAsync", async () => { }); } return data.length; - }) - .safeParseAsync("asdf"); + }), + "asdf" + ); expect(JSON.parse(JSON.stringify(result))).toEqual({ success: false, @@ -87,7 +87,7 @@ test("z.NEVER in transform", () => { }); type foo = z.infer; util.assertEqual(true); - const arg = foo.safeParse(undefined); + const arg = z.safeParse(foo, undefined); if (!arg.success) { expect(arg.error.issues[0].message).toEqual("bad"); } @@ -202,13 +202,13 @@ test("short circuit on dirty", () => { .string() .refine(() => false) .transform((val) => val.toUpperCase()); - const result = schema.safeParse("asdf"); + const result = z.safeParse(schema, "asdf"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.custom); } - const result2 = schema.safeParse(1234); + const result2 = z.safeParse(schema, 1234); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_type); @@ -220,13 +220,13 @@ test("async short circuit on dirty", async () => { .string() .refine(() => false) .transform((val) => val.toUpperCase()); - const result = await schema.spa("asdf"); + const result = await z.spa(schema, "asdf"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.custom); } - const result2 = await schema.spa(1234); + const result2 = await z.spa(schema, 1234); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_type); diff --git a/deno/lib/__tests__/tuple.test.ts b/deno/lib/__tests__/tuple.test.ts index 77d1845c0..c55638dde 100644 --- a/deno/lib/__tests__/tuple.test.ts +++ b/deno/lib/__tests__/tuple.test.ts @@ -46,7 +46,7 @@ test("failed validation", () => { }); test("failed async validation", async () => { - const res = await testTuple.safeParse(badData); + const res = await z.safeParse(testTuple, badData); expect(res.success).toEqual(false); if (!res.success) { expect(res.error.issues.length).toEqual(3); diff --git a/deno/lib/__tests__/unions.test.ts b/deno/lib/__tests__/unions.test.ts index 3a73d975f..f4d6f5324 100644 --- a/deno/lib/__tests__/unions.test.ts +++ b/deno/lib/__tests__/unions.test.ts @@ -9,14 +9,15 @@ test("function parsing", () => { z.string().refine(() => false), z.number().refine(() => false), ]); - const result = schema.safeParse("asdf"); + const result = z.safeParse(schema, "asdf"); expect(result.success).toEqual(false); }); test("union 2", () => { - const result = z - .union([z.number(), z.string().refine(() => false)]) - .safeParse("a"); + const result = z.safeParse( + z.union([z.number(), z.string().refine(() => false)]), + "a" + ); expect(result.success).toEqual(false); }); @@ -34,9 +35,10 @@ test("return valid over invalid", () => { }); test("return dirty result over aborted", () => { - const result = z - .union([z.number(), z.string().refine(() => false)]) - .safeParse("a"); + const result = z.safeParse( + z.union([z.number(), z.string().refine(() => false)]), + "a" + ); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues).toEqual([ diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 1eef61f14..59d82fdb4 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -5242,24 +5242,15 @@ export async function safeParseAsync( /** Alias of safeParseAsync */ export const spa = safeParseAsync; -export function catch_< - Output, - Input, - Schema extends ZodType ->(schema: Schema, def: Output): ZodCatch; -export function catch_< - Output, - Input, - Schema extends ZodType ->( +export function catch_( schema: Schema, - def: (ctx: { error: ZodError; input: Input }) => Output + def: output ): ZodCatch; -export function catch_< - Output, - Input, - Schema extends ZodType ->(schema: Schema, def: any) { +export function catch_( + schema: Schema, + def: (ctx: { error: ZodError; input: input }) => output +): ZodCatch; +export function catch_(schema: Schema, def: any) { const catchValueFunc = typeof def === "function" ? def : () => def; return new ZodCatch({ diff --git a/src/__tests__/all-errors.test.ts b/src/__tests__/all-errors.test.ts index 7b5999b42..6a89a282d 100644 --- a/src/__tests__/all-errors.test.ts +++ b/src/__tests__/all-errors.test.ts @@ -59,7 +59,7 @@ test("form errors type inference", () => { }); test(".flatten() type assertion", () => { - const parsed = Test.safeParse({}) as z.SafeParseError; + const parsed = z.safeParse(Test, {}) as z.SafeParseError; const validFlattenedErrors: TestFlattenedErrors = parsed.error.flatten( () => ({ message: "", code: 0 }) ); @@ -81,7 +81,7 @@ test(".flatten() type assertion", () => { }); test(".formErrors type assertion", () => { - const parsed = Test.safeParse({}) as z.SafeParseError; + const parsed = z.safeParse(Test, {}) as z.SafeParseError; const validFormErrors: TestFormErrors = parsed.error.formErrors; // @ts-expect-error should fail assertion between `TestFlattenedErrors` and `.formErrors`. const invalidFlattenedErrors: TestFlattenedErrors = parsed.error.formErrors; diff --git a/src/__tests__/array.test.ts b/src/__tests__/array.test.ts index 21ae44bee..dffb41f94 100644 --- a/src/__tests__/array.test.ts +++ b/src/__tests__/array.test.ts @@ -55,7 +55,7 @@ test("continue parsing despite array size error", () => { people: z.string().array().min(2), }); - const result = schema.safeParse({ + const result = z.safeParse(schema, { people: [123], }); expect(result.success).toEqual(false); diff --git a/src/__tests__/async-parsing.test.ts b/src/__tests__/async-parsing.test.ts index 4970f32d0..024b34612 100644 --- a/src/__tests__/async-parsing.test.ts +++ b/src/__tests__/async-parsing.test.ts @@ -10,11 +10,11 @@ test("string async parse", async () => { const goodData = "XXX"; const badData = 12; - const goodResult = await stringSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(stringSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await stringSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(stringSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -25,11 +25,11 @@ test("number async parse", async () => { const goodData = 1234.2353; const badData = "1234"; - const goodResult = await numberSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(numberSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await numberSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(numberSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -40,11 +40,11 @@ test("bigInt async parse", async () => { const goodData = BigInt(145); const badData = 134; - const goodResult = await bigIntSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(bigIntSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await bigIntSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(bigIntSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -55,11 +55,11 @@ test("boolean async parse", async () => { const goodData = true; const badData = 1; - const goodResult = await booleanSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(booleanSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await booleanSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(booleanSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -70,11 +70,11 @@ test("date async parse", async () => { const goodData = new Date(); const badData = new Date().toISOString(); - const goodResult = await dateSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(dateSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await dateSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(dateSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -85,11 +85,11 @@ test("undefined async parse", async () => { const goodData = undefined; const badData = "XXX"; - const goodResult = await undefinedSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(undefinedSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(undefined); - const badResult = await undefinedSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(undefinedSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -100,11 +100,11 @@ test("null async parse", async () => { const goodData = null; const badData = undefined; - const goodResult = await nullSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(nullSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await nullSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(nullSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -115,11 +115,11 @@ test("any async parse", async () => { const goodData = [{}]; // const badData = 'XXX'; - const goodResult = await anySchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(anySchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - // const badResult = await anySchema.safeParseAsync(badData); + // const badResult = await z.safeParseAsync(anySchema, badData); // expect(badResult.success).toBe(false); // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -130,11 +130,11 @@ test("unknown async parse", async () => { const goodData = ["asdf", 124, () => {}]; // const badData = 'XXX'; - const goodResult = await unknownSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(unknownSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - // const badResult = await unknownSchema.safeParseAsync(badData); + // const badResult = await z.safeParseAsync(unknownSchema, badData); // expect(badResult.success).toBe(false); // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -145,11 +145,11 @@ test("void async parse", async () => { const goodData = undefined; const badData = 0; - const goodResult = await voidSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(voidSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await voidSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(voidSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -160,11 +160,11 @@ test("array async parse", async () => { const goodData = ["XXX"]; const badData = "XXX"; - const goodResult = await arraySchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(arraySchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await arraySchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(arraySchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -175,11 +175,11 @@ test("object async parse", async () => { const goodData = { string: "XXX" }; const badData = { string: 12 }; - const goodResult = await objectSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(objectSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await objectSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(objectSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -190,11 +190,11 @@ test("union async parse", async () => { const goodData = undefined; const badData = null; - const goodResult = await unionSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(unionSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await unionSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(unionSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -205,11 +205,11 @@ test("record async parse", async () => { const goodData = { adsf: {}, asdf: {} }; const badData = [{}]; - const goodResult = await recordSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(recordSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await recordSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(recordSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -220,11 +220,11 @@ test("function async parse", async () => { const goodData = () => {}; const badData = "XXX"; - const goodResult = await functionSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(functionSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(typeof goodResult.data).toEqual("function"); - const badResult = await functionSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(functionSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -235,11 +235,11 @@ test("literal async parse", async () => { const goodData = "asdf"; const badData = "asdff"; - const goodResult = await literalSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(literalSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await literalSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(literalSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -250,11 +250,11 @@ test("enum async parse", async () => { const goodData = "whale"; const badData = "leopard"; - const goodResult = await enumSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(enumSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await enumSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(enumSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -269,11 +269,11 @@ test("nativeEnum async parse", async () => { const goodData = nativeEnumTest.asdf; const badData = "asdf"; - const goodResult = await nativeEnumSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(nativeEnumSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) expect(goodResult.data).toEqual(goodData); - const badResult = await nativeEnumSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(nativeEnumSchema, badData); expect(badResult.success).toBe(false); if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError); }); @@ -283,7 +283,7 @@ const promiseSchema = z.promise(z.number()); test("promise async parse good", async () => { const goodData = Promise.resolve(123); - const goodResult = await promiseSchema.safeParseAsync(goodData); + const goodResult = await z.safeParseAsync(promiseSchema, goodData); expect(goodResult.success).toBe(true); if (goodResult.success) { expect(goodResult.data).toBeInstanceOf(Promise); @@ -298,7 +298,7 @@ test("promise async parse good", async () => { test("promise async parse bad", async () => { const badData = Promise.resolve("XXX"); - const badResult = await promiseSchema.safeParseAsync(badData); + const badResult = await z.safeParseAsync(promiseSchema, badData); expect(badResult.success).toBe(true); if (badResult.success) { await expect(badResult.data).rejects.toBeInstanceOf(z.ZodError); @@ -314,8 +314,8 @@ test("async validation non-empty strings", async () => { }); const testval = { hello: "", foo: "" }; - const result1 = base.safeParse(testval); - const result2 = base.safeParseAsync(testval); + const result1 = z.safeParse(base, testval); + const result2 = z.safeParseAsync(base, testval); const r1 = result1; await result2.then((r2) => { @@ -331,8 +331,8 @@ test("async validation multiple errors 1", async () => { }); const testval = { hello: 3, foo: "hello" }; - const result1 = base.safeParse(testval); - const result2 = base.safeParseAsync(testval); + const result1 = z.safeParse(base, testval); + const result2 = z.safeParseAsync(base, testval); const r1 = result1; await result2.then((r2) => { @@ -351,8 +351,8 @@ test("async validation multiple errors 2", async () => { }); const testval = { hello: 3, foo: { bar: 4 } }; - const result1 = base().safeParse(testval); - const result2 = base(true).safeParseAsync(testval); + const result1 = z.safeParse(base(), testval); + const result2 = z.safeParseAsync(base(true), testval); const r1 = result1; await result2.then((r2) => { @@ -378,7 +378,7 @@ test("ensure early async failure prevents follow-up refinement checks", async () }); const testval = { hello: "bye", foo: 3 }; - const result = await base.safeParseAsync(testval); + const result = await z.safeParseAsync(base, testval); if (result.success === false) { expect(result.error.issues.length).toBe(1); expect(count).toBe(1); diff --git a/src/__tests__/base.test.ts b/src/__tests__/base.test.ts index 9c5eeac6b..8e8c1e452 100644 --- a/src/__tests__/base.test.ts +++ b/src/__tests__/base.test.ts @@ -13,7 +13,7 @@ test("type guard", () => { type t1 = z.input; const data = { stringToNumber: "asdf" }; - const parsed = s1.safeParse(data); + const parsed = z.safeParse(s1, data); if (parsed.success) { util.assertEqual(true); } @@ -24,6 +24,10 @@ test("test this binding", () => { return predicate("hello"); }; - expect(callback((value) => z.string().safeParse(value).success)).toBe(true); // true - expect(callback((value) => z.string().safeParse(value).success)).toBe(true); // true + expect(callback((value) => z.safeParse(z.string(), value).success)).toBe( + true + ); // true + expect(callback((value) => z.safeParse(z.string(), value).success)).toBe( + true + ); // true }); diff --git a/src/__tests__/catch.test.ts b/src/__tests__/catch.test.ts index ae0ebe0a4..9655c2027 100644 --- a/src/__tests__/catch.test.ts +++ b/src/__tests__/catch.test.ts @@ -5,7 +5,7 @@ import { z } from ".."; import { util } from "../helpers/util"; test("basic catch", () => { - expect(z.string().catch("default").parse(undefined)).toBe("default"); + expect(z.catch_(z.string(), "default").parse(undefined)).toBe("default"); }); test("catch fn does not run when parsing succeeds", () => { @@ -14,30 +14,30 @@ test("catch fn does not run when parsing succeeds", () => { isCalled = true; return "asdf"; }; - expect(z.string().catch(cb).parse("test")).toBe("test"); + expect(z.catch_(z.string(), cb).parse("test")).toBe("test"); expect(isCalled).toEqual(false); }); test("basic catch async", async () => { - const result = await z.string().catch("default").parseAsync(1243); + const result = await z.catch_(z.string(), "default").parseAsync(1243); expect(result).toBe("default"); }); test("catch replace wrong types", () => { - expect(z.string().catch("default").parse(true)).toBe("default"); - expect(z.string().catch("default").parse(true)).toBe("default"); - expect(z.string().catch("default").parse(15)).toBe("default"); - expect(z.string().catch("default").parse([])).toBe("default"); - expect(z.string().catch("default").parse(new Map())).toBe("default"); - expect(z.string().catch("default").parse(new Set())).toBe("default"); - expect(z.string().catch("default").parse({})).toBe("default"); + expect(z.catch_(z.string(), "default").parse(true)).toBe("default"); + expect(z.catch_(z.string(), "default").parse(true)).toBe("default"); + expect(z.catch_(z.string(), "default").parse(15)).toBe("default"); + expect(z.catch_(z.string(), "default").parse([])).toBe("default"); + expect(z.catch_(z.string(), "default").parse(new Map())).toBe("default"); + expect(z.catch_(z.string(), "default").parse(new Set())).toBe("default"); + expect(z.catch_(z.string(), "default").parse({})).toBe("default"); }); test("catch with transform", () => { - const stringWithDefault = z - .string() - .transform((val) => val.toUpperCase()) - .catch("default"); + const stringWithDefault = z.catch_( + z.string().transform((val) => val.toUpperCase()), + "default" + ); expect(stringWithDefault.parse(undefined)).toBe("default"); expect(stringWithDefault.parse(15)).toBe("default"); expect(stringWithDefault).toBeInstanceOf(z.ZodCatch); @@ -53,7 +53,7 @@ test("catch with transform", () => { }); test("catch on existing optional", () => { - const stringWithDefault = z.string().optional().catch("asdf"); + const stringWithDefault = z.catch_(z.string().optional(), "asdf"); expect(stringWithDefault.parse(undefined)).toBe(undefined); expect(stringWithDefault.parse(15)).toBe("asdf"); expect(stringWithDefault).toBeInstanceOf(z.ZodCatch); @@ -69,7 +69,7 @@ test("catch on existing optional", () => { }); test("optional on catch", () => { - const stringWithDefault = z.string().catch("asdf").optional(); + const stringWithDefault = z.catch_(z.string(), "asdf").optional(); type inp = z.input; util.assertEqual(true); @@ -78,15 +78,19 @@ test("optional on catch", () => { }); test("complex chain example", () => { - const complex = z - .string() - .catch("asdf") - .transform((val) => val + "!") - .transform((val) => val.toUpperCase()) - .catch("qwer") - .removeCatch() - .optional() - .catch("asdfasdf"); + const complex = z.catch_( + z + .catch_( + z + .catch_(z.string(), "asdf") + .transform((val) => val + "!") + .transform((val) => val.toUpperCase()), + "qwer" + ) + .removeCatch() + .optional(), + "asdfasdf" + ); expect(complex.parse("qwer")).toBe("QWER!"); expect(complex.parse(15)).toBe("ASDF!"); @@ -94,15 +98,15 @@ test("complex chain example", () => { }); test("removeCatch", () => { - const stringWithRemovedDefault = z.string().catch("asdf").removeCatch(); + const stringWithRemovedDefault = z.catch_(z.string(), "asdf").removeCatch(); type out = z.output; util.assertEqual(true); }); test("nested", () => { - const inner = z.string().catch("asdf"); - const outer = z.object({ inner }).catch({ + const inner = z.catch_(z.string(), "asdf"); + const outer = z.catch_(z.object({ inner }), { inner: "asdf", }); type input = z.input; @@ -115,7 +119,7 @@ test("nested", () => { }); test("chained catch", () => { - const stringWithDefault = z.string().catch("inner").catch("outer"); + const stringWithDefault = z.catch_(z.catch_(z.string(), "inner"), "outer"); const result = stringWithDefault.parse(undefined); expect(result).toEqual("inner"); const resultDiff = stringWithDefault.parse(5); @@ -135,7 +139,7 @@ test("native enum", () => { } const schema = z.object({ - fruit: z.nativeEnum(Fruits).catch(Fruits.apple), + fruit: z.catch_(z.nativeEnum(Fruits), Fruits.apple), }); expect(schema.parse({})).toEqual({ fruit: Fruits.apple }); @@ -144,7 +148,7 @@ test("native enum", () => { test("enum", () => { const schema = z.object({ - fruit: z.enum(["apple", "orange"]).catch("apple"), + fruit: z.catch_(z.enum(["apple", "orange"]), "apple"), }); expect(schema.parse({})).toEqual({ fruit: "apple" }); @@ -158,11 +162,11 @@ test("reported issues with nested usage", () => { obj: z.object({ sub: z.object({ lit: z.literal("a"), - subCatch: z.number().catch(23), + subCatch: z.catch_(z.number(), 23), }), - midCatch: z.number().catch(42), + midCatch: z.catch_(z.number(), 42), }), - number: z.number().catch(0), + number: z.catch_(z.number(), 0), bool: z.boolean(), }); @@ -194,14 +198,14 @@ test("catch error", () => { const schema = z.object({ age: z.number(), - name: z.string().catch((ctx) => { + name: z.catch_(z.string(), (ctx) => { catchError = ctx.error; return "John Doe"; }), }); - const result = schema.safeParse({ + const result = z.safeParse(schema, { age: null, name: null, }); @@ -220,7 +224,7 @@ test("catch error", () => { }); test("ctx.input", () => { - const schema = z.string().catch((ctx) => { + const schema = z.catch_(z.string(), (ctx) => { return String(ctx.input); }); diff --git a/src/__tests__/custom.test.ts b/src/__tests__/custom.test.ts index 0fb9ca46c..985060cf1 100644 --- a/src/__tests__/custom.test.ts +++ b/src/__tests__/custom.test.ts @@ -11,7 +11,7 @@ test("passing validations", () => { test("string params", () => { const example1 = z.custom((x) => typeof x !== "number", "customerr"); - const result = example1.safeParse(1234); + const result = z.safeParse(example1, 1234); expect(result.success).toEqual(false); // @ts-ignore expect(JSON.stringify(result.error).includes("customerr")).toEqual(true); diff --git a/src/__tests__/enum.test.ts b/src/__tests__/enum.test.ts index 75c79abfd..7bbfe210e 100644 --- a/src/__tests__/enum.test.ts +++ b/src/__tests__/enum.test.ts @@ -32,9 +32,10 @@ test("readonly enum", () => { }); test("error params", () => { - const result = z - .enum(["test"], { required_error: "REQUIRED" }) - .safeParse(undefined); + const result = z.safeParse( + z.enum(["test"], { required_error: "REQUIRED" }), + undefined + ); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("REQUIRED"); @@ -64,8 +65,8 @@ test("error map in extract/exclude", () => { errorMap: () => ({ message: "This is not food!" }), }); const ItalianEnum = FoodEnum.extract(["Pasta", "Pizza"]); - const foodsError = FoodEnum.safeParse("Cucumbers"); - const italianError = ItalianEnum.safeParse("Tacos"); + const foodsError = z.safeParse(FoodEnum, "Cucumbers"); + const italianError = z.safeParse(ItalianEnum, "Tacos"); if (!foodsError.success && !italianError.success) { expect(foodsError.error.issues[0].message).toEqual( italianError.error.issues[0].message @@ -75,7 +76,7 @@ test("error map in extract/exclude", () => { const UnhealthyEnum = FoodEnum.exclude(["Salad"], { errorMap: () => ({ message: "This is not healthy food!" }), }); - const unhealthyError = UnhealthyEnum.safeParse("Salad"); + const unhealthyError = z.safeParse(UnhealthyEnum, "Salad"); if (!unhealthyError.success) { expect(unhealthyError.error.issues[0].message).toEqual( "This is not healthy food!" diff --git a/src/__tests__/error.test.ts b/src/__tests__/error.test.ts index b1942743b..3e73207c8 100644 --- a/src/__tests__/error.test.ts +++ b/src/__tests__/error.test.ts @@ -164,7 +164,7 @@ test("custom path in custom error map", () => { expect(error.path.length).toBe(2); return { message: "doesnt matter" }; }; - const result = schema.safeParse({ items: ["first"] }, { errorMap }); + const result = z.safeParse(schema, { items: ["first"] }, { errorMap }); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].path).toEqual(["items", "items-too-few"]); @@ -177,7 +177,7 @@ test("error metadata from value", () => { (val) => ({ params: { val } }) ); - const result = dynamicRefine.safeParse("asdf"); + const result = z.safeParse(dynamicRefine, "asdf"); expect(result.success).toEqual(false); if (!result.success) { const sub = result.error.issues[0]; @@ -198,12 +198,12 @@ test("error metadata from value", () => { // ]) // .refine((v) => v >= 1); -// expect(() => asdf.safeParse("foo")).not.toThrow(); +// expect(() => z.safeParse(asdf, "foo")).not.toThrow(); // }); test("root level formatting", () => { const schema = z.string().email(); - const result = schema.safeParse("asdfsdf"); + const result = z.safeParse(schema, "asdfsdf"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.format()._errors).toEqual(["Invalid email"]); @@ -218,7 +218,7 @@ test("custom path", () => { }) .refine((val) => val.confirm === val.password, { path: ["confirm"] }); - const result = schema.safeParse({ + const result = z.safeParse(schema, { password: "peanuts", confirm: "qeanuts", }); @@ -241,7 +241,7 @@ test("custom path", () => { }) .refine((val) => val.confirm === val.password); - const result = schema.safeParse({ + const result = z.safeParse(schema, { password: "qwer", confirm: "asdf", }); @@ -267,7 +267,7 @@ test("no abort early on refinements", () => { inner: { name: ["aasd", "asdfasdfasfd"] }, }; - const result1 = schema.safeParse(invalidItem); + const result1 = z.safeParse(schema, invalidItem); expect(result1.success).toEqual(false); if (!result1.success) { expect(result1.error.issues.length).toEqual(2); @@ -280,8 +280,8 @@ test("formatting", () => { const invalidArray = { inner: { name: ["asdfasdf", "asdfasdfasfd"] }, }; - const result1 = schema.safeParse(invalidItem); - const result2 = schema.safeParse(invalidArray); + const result1 = z.safeParse(schema, invalidItem); + const result2 = z.safeParse(schema, invalidArray); expect(result1.success).toEqual(false); expect(result2.success).toEqual(false); @@ -333,7 +333,7 @@ test("formatting with nullable and optional fields", () => { optionalArray: ["abcd"], optionalTuple: ["abcd", "abcd", 1], }; - const result = schema.safeParse(invalidItem); + const result = z.safeParse(schema, invalidItem); expect(result.success).toEqual(false); if (!result.success) { type FormattedError = z.inferFormattedError; @@ -368,20 +368,20 @@ const stringWithCustomError = z.string({ }); test("schema-bound error map", () => { - const result = stringWithCustomError.safeParse(1234); + const result = z.safeParse(stringWithCustomError, 1234); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("Invalid name"); } - const result2 = stringWithCustomError.safeParse(undefined); + const result2 = z.safeParse(stringWithCustomError, undefined); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].message).toEqual("Name is required"); } // support contextual override - const result3 = stringWithCustomError.safeParse(undefined, { + const result3 = z.safeParse(stringWithCustomError, undefined, { errorMap: () => ({ message: "OVERRIDE" }), }); expect(result3.success).toEqual(false); @@ -393,7 +393,7 @@ test("schema-bound error map", () => { test("overrideErrorMap", () => { // support overrideErrorMap z.setErrorMap(() => ({ message: "OVERRIDE" })); - const result4 = stringWithCustomError.min(10).safeParse("tooshort"); + const result4 = z.safeParse(stringWithCustomError.min(10), "tooshort"); expect(result4.success).toEqual(false); if (!result4.success) { expect(result4.error.issues[0].message).toEqual("OVERRIDE"); @@ -406,12 +406,12 @@ test("invalid and required", () => { invalid_type_error: "Invalid name", required_error: "Name is required", }); - const result1 = str.safeParse(1234); + const result1 = z.safeParse(str, 1234); expect(result1.success).toEqual(false); if (!result1.success) { expect(result1.error.issues[0].message).toEqual("Invalid name"); } - const result2 = str.safeParse(undefined); + const result2 = z.safeParse(str, undefined); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].message).toEqual("Name is required"); @@ -424,7 +424,7 @@ test("Fallback to default required error", () => { // required_error: "Name is required", }); - const result2 = str.safeParse(undefined); + const result2 = z.safeParse(str, undefined); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].message).toEqual("Required"); @@ -444,7 +444,7 @@ test("invalid and required and errorMap", () => { test("strict error message", () => { const errorMsg = "Invalid object"; const obj = z.object({ x: z.string() }).strict(errorMsg); - const result = obj.safeParse({ x: "a", y: "b" }); + const result = z.safeParse(obj, { x: "a", y: "b" }); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual(errorMsg); @@ -520,7 +520,7 @@ test("enum with message returns the custom error message", () => { message: "the value provided is invalid", }); - const result1 = schema.safeParse("berries"); + const result1 = z.safeParse(schema, "berries"); expect(result1.success).toEqual(false); if (!result1.success) { expect(result1.error.issues[0].message).toEqual( @@ -528,7 +528,7 @@ test("enum with message returns the custom error message", () => { ); } - const result2 = schema.safeParse(undefined); + const result2 = z.safeParse(schema, undefined); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].message).toEqual( @@ -536,10 +536,10 @@ test("enum with message returns the custom error message", () => { ); } - const result3 = schema.safeParse("banana"); + const result3 = z.safeParse(schema, "banana"); expect(result3.success).toEqual(true); - const result4 = schema.safeParse(null); + const result4 = z.safeParse(schema, null); expect(result4.success).toEqual(false); if (!result4.success) { expect(result4.error.issues[0].message).toEqual( @@ -550,7 +550,7 @@ test("enum with message returns the custom error message", () => { test("when the message is falsy, it is used as is provided", () => { const schema = z.string().max(1, { message: "" }); - const result = schema.safeParse("asdf"); + const result = z.safeParse(schema, "asdf"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual(""); @@ -567,7 +567,7 @@ test("when the message is falsy, it is used as is provided", () => { // message: "Passwords don't match", // path: ["confirm"], // }); -// const result = user.safeParse({ password: "asdf", confirm: "qwer" }); +// const result = z.safeParse(user, { password: "asdf", confirm: "qwer" }); // if (!result.success) { // expect(result.error.issues.length).toEqual(2); // } diff --git a/src/__tests__/generics.test.ts b/src/__tests__/generics.test.ts index c31c7f605..ae36def9c 100644 --- a/src/__tests__/generics.test.ts +++ b/src/__tests__/generics.test.ts @@ -47,5 +47,5 @@ test("nested no undefined", () => { const outer = z.object({ inner }); type outerSchema = z.infer; z.util.assertEqual(true); - expect(outer.safeParse({ inner: undefined }).success).toEqual(false); + expect(z.safeParse(outer, { inner: undefined }).success).toEqual(false); }); diff --git a/src/__tests__/instanceof.test.ts b/src/__tests__/instanceof.test.ts index 4175f487f..4468640bf 100644 --- a/src/__tests__/instanceof.test.ts +++ b/src/__tests__/instanceof.test.ts @@ -36,6 +36,6 @@ test("instanceof", async () => { test("instanceof fatal", () => { const schema = z.instanceof(Date).refine((d) => d.toString()); - const res = schema.safeParse(null); + const res = z.safeParse(schema, null); expect(res.success).toBe(false); }); diff --git a/src/__tests__/intersection.test.ts b/src/__tests__/intersection.test.ts index de9255d80..5daaac8a9 100644 --- a/src/__tests__/intersection.test.ts +++ b/src/__tests__/intersection.test.ts @@ -77,7 +77,7 @@ test("invalid intersection types", async () => { z.number().transform((x) => x + 1) ); - const syncResult = numberIntersection.safeParse(1234); + const syncResult = z.safeParse(numberIntersection, 1234); expect(syncResult.success).toEqual(false); if (!syncResult.success) { expect(syncResult.error.issues[0].code).toEqual( @@ -85,7 +85,7 @@ test("invalid intersection types", async () => { ); } - const asyncResult = await numberIntersection.spa(1234); + const asyncResult = await z.spa(numberIntersection, 1234); expect(asyncResult.success).toEqual(false); if (!asyncResult.success) { expect(asyncResult.error.issues[0].code).toEqual( @@ -102,7 +102,7 @@ test("invalid array merge", async () => { .array() .transform((val) => [...val, "asdf"]) ); - const syncResult = stringArrInt.safeParse(["asdf", "qwer"]); + const syncResult = z.safeParse(stringArrInt, ["asdf", "qwer"]); expect(syncResult.success).toEqual(false); if (!syncResult.success) { expect(syncResult.error.issues[0].code).toEqual( @@ -110,7 +110,7 @@ test("invalid array merge", async () => { ); } - const asyncResult = await stringArrInt.spa(["asdf", "qwer"]); + const asyncResult = await z.spa(stringArrInt, ["asdf", "qwer"]); expect(asyncResult.success).toEqual(false); if (!asyncResult.success) { expect(asyncResult.error.issues[0].code).toEqual( diff --git a/src/__tests__/literal.test.ts b/src/__tests__/literal.test.ts index 140f728e6..ca1300dac 100644 --- a/src/__tests__/literal.test.ts +++ b/src/__tests__/literal.test.ts @@ -26,7 +26,7 @@ test("failing validations", () => { test("invalid_literal should have `received` field with data", () => { const data = "shark"; - const result = literalTuna.safeParse(data); + const result = z.safeParse(literalTuna, data); if (!result.success) { const issue = result.error.issues[0]; if (issue.code === "invalid_literal") { diff --git a/src/__tests__/map.test.ts b/src/__tests__/map.test.ts index 08405db3d..6f194c7b8 100644 --- a/src/__tests__/map.test.ts +++ b/src/__tests__/map.test.ts @@ -13,7 +13,8 @@ test("type inference", () => { }); test("valid parse", () => { - const result = stringMap.safeParse( + const result = z.safeParse( + stringMap, new Map([ ["first", "foo"], ["second", "bar"], @@ -29,7 +30,8 @@ test("valid parse", () => { }); test("valid parse async", async () => { - const result = await stringMap.spa( + const result = await z.spa( + stringMap, new Map([ ["first", "foo"], ["second", "bar"], @@ -45,7 +47,7 @@ test("valid parse async", async () => { }); test("throws when a Set is given", () => { - const result = stringMap.safeParse(new Set([])); + const result = z.safeParse(stringMap, new Set([])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(1); @@ -54,7 +56,7 @@ test("throws when a Set is given", () => { }); test("throws when the given map has invalid key and invalid input", () => { - const result = stringMap.safeParse(new Map([[42, Symbol()]])); + const result = z.safeParse(stringMap, new Map([[42, Symbol()]])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(2); @@ -66,16 +68,17 @@ test("throws when the given map has invalid key and invalid input", () => { }); test("throws when the given map has multiple invalid entries", () => { - // const result = stringMap.safeParse(new Map([[42, Symbol()]])); + // const result = z.safeParse(stringMap, new Map([[42, Symbol()]])); - const result = stringMap.safeParse( + const result = z.safeParse( + stringMap, new Map([ [1, "foo"], ["bar", 2], ] as [any, any][]) as Map ); - // const result = stringMap.safeParse(new Map([[42, Symbol()]])); + // const result = z.safeParse(stringMap, new Map([[42, Symbol()]])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(2); @@ -93,7 +96,8 @@ test("dirty", async () => { }), z.string() ); - const result = await map.spa( + const result = await z.spa( + map, new Map([ ["first", "foo"], ["second", "bar"], diff --git a/src/__tests__/object-in-es5-env.test.ts b/src/__tests__/object-in-es5-env.test.ts index 6d17a0964..8dbf47fce 100644 --- a/src/__tests__/object-in-es5-env.test.ts +++ b/src/__tests__/object-in-es5-env.test.ts @@ -9,21 +9,21 @@ const RealDate = Date; test("doesn’t throw when Date is undefined", () => { delete (globalThis as any).Date; - const result = z.object({}).safeParse({}); + const result = z.safeParse(z.object({}), {}); expect(result.success).toEqual(true); globalThis.Date = RealDate; }); test("doesn’t throw when Set is undefined", () => { delete (globalThis as any).Set; - const result = z.object({}).safeParse({}); + const result = z.safeParse(z.object({}), {}); expect(result.success).toEqual(true); globalThis.Set = RealSet; }); test("doesn’t throw when Map is undefined", () => { delete (globalThis as any).Map; - const result = z.object({}).safeParse({}); + const result = z.safeParse(z.object({}), {}); expect(result.success).toEqual(true); globalThis.Map = RealMap; }); diff --git a/src/__tests__/object.test.ts b/src/__tests__/object.test.ts index 879351f83..ad63302f4 100644 --- a/src/__tests__/object.test.ts +++ b/src/__tests__/object.test.ts @@ -109,7 +109,7 @@ test("strip unknown", () => { }); test("strict", () => { - const val = z.object({ points: z.number() }).strict().safeParse(data); + const val = z.safeParse(z.object({ points: z.number() }).strict(), data); expect(val.success).toEqual(false); }); @@ -184,10 +184,10 @@ test("test catchall parsing", async () => { expect(result).toEqual({ name: "Foo", validExtraKey: 61 }); - const result2 = z - .object({ name: z.string() }) - .catchall(z.number()) - .safeParse({ name: "Foo", validExtraKey: 61, invalid: "asdf" }); + const result2 = z.safeParse( + z.object({ name: z.string() }).catchall(z.number()), + { name: "Foo", validExtraKey: 61, invalid: "asdf" } + ); expect(result2.success).toEqual(false); }); @@ -198,7 +198,7 @@ test("test nonexistent keys", async () => { z.object({ b: z.number() }), ]); const obj = { a: "A" }; - const result = await Schema.spa(obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 + const result = await z.spa(Schema, obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 expect(result.success).toBe(true); }); @@ -213,7 +213,7 @@ test("test async union", async () => { ]); const obj = { ty: "A" }; - const result = await Schema2.spa(obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 + const result = await z.spa(Schema2, obj); // Works with 1.11.10, breaks with 2.0.0-beta.21 expect(result.success).toEqual(true); }); @@ -310,10 +310,10 @@ test("strictcreate", async () => { name: z.string(), }); - const syncResult = strictObj.safeParse({ name: "asdf", unexpected: 13 }); + const syncResult = z.safeParse(strictObj, { name: "asdf", unexpected: 13 }); expect(syncResult.success).toEqual(false); - const asyncResult = await strictObj.spa({ name: "asdf", unexpected: 13 }); + const asyncResult = await z.spa(strictObj, { name: "asdf", unexpected: 13 }); expect(asyncResult.success).toEqual(false); }); diff --git a/src/__tests__/partials.test.ts b/src/__tests__/partials.test.ts index 3186c9f97..5eb0ee330 100644 --- a/src/__tests__/partials.test.ts +++ b/src/__tests__/partials.test.ts @@ -248,5 +248,5 @@ test("deeppartial array", () => { schema.parse({}); // should be false, but is true - expect(schema.safeParse({ array: [] }).success).toBe(false); + expect(z.safeParse(schema, { array: [] }).success).toBe(false); }); diff --git a/src/__tests__/pipeline.test.ts b/src/__tests__/pipeline.test.ts index a977f1ef6..9b0fdecf2 100644 --- a/src/__tests__/pipeline.test.ts +++ b/src/__tests__/pipeline.test.ts @@ -22,8 +22,8 @@ test("break if dirty", () => { .refine((c) => c === "1234") .transform(async (val) => Number(val)) .pipe(z.number().refine((v) => v < 100)); - const r1: any = schema.safeParse("12345"); + const r1: any = z.safeParse(schema, "12345"); expect(r1.error.issues.length).toBe(1); - const r2: any = schema.safeParse("3"); + const r2: any = z.safeParse(schema, "3"); expect(r2.error.issues.length).toBe(1); }); diff --git a/src/__tests__/preprocess.test.ts b/src/__tests__/preprocess.test.ts index 271d293ae..0ee2261ac 100644 --- a/src/__tests__/preprocess.test.ts +++ b/src/__tests__/preprocess.test.ts @@ -9,7 +9,7 @@ test("preprocess", () => { const value = schema.parse("asdf"); expect(value).toEqual(["asdf"]); - util.assertEqual<(typeof schema)["_input"], unknown>(true); + util.assertEqual, unknown>(true); }); test("async preprocess", async () => { @@ -99,15 +99,16 @@ test("async preprocess ctx.addIssue with parse", async () => { }); test("preprocess ctx.addIssue with parseAsync", async () => { - const result = await z - .preprocess(async (data, ctx) => { + const result = await z.safeParseAsync( + z.preprocess(async (data, ctx) => { ctx.addIssue({ code: "custom", message: `${data} is not one of our allowed strings`, }); return data; - }, z.string()) - .safeParseAsync("asdf"); + }, z.string()), + "asdf" + ); expect(JSON.parse(JSON.stringify(result))).toEqual({ success: false, @@ -135,7 +136,7 @@ test("z.NEVER in preprocess", () => { type foo = z.infer; util.assertEqual(true); - const arg = foo.safeParse(undefined); + const arg = z.safeParse(foo, undefined); if (!arg.success) { expect(arg.error.issues[0].message).toEqual("bad"); } @@ -145,7 +146,7 @@ test("preprocess as the second property of object", () => { nonEmptyStr: z.string().min(1), positiveNum: z.preprocess((v) => Number(v), z.number().positive()), }); - const result = schema.safeParse({ + const result = z.safeParse(schema, { nonEmptyStr: "", positiveNum: "", }); diff --git a/src/__tests__/record.test.ts b/src/__tests__/record.test.ts index 86f60b267..b3409a414 100644 --- a/src/__tests__/record.test.ts +++ b/src/__tests__/record.test.ts @@ -155,7 +155,7 @@ test("is not vulnerable to prototype pollution", async () => { const obj1 = rec.parse(data); expect(obj1.a).toBeUndefined(); - const obj2 = rec.safeParse(data); + const obj2 = z.safeParse(rec, data); expect(obj2.success).toBe(true); if (obj2.success) { expect(obj2.data.a).toBeUndefined(); @@ -164,7 +164,7 @@ test("is not vulnerable to prototype pollution", async () => { const obj3 = await rec.parseAsync(data); expect(obj3.a).toBeUndefined(); - const obj4 = await rec.safeParseAsync(data); + const obj4 = await z.safeParseAsync(rec, data); expect(obj4.success).toBe(true); if (obj4.success) { expect(obj4.data.a).toBeUndefined(); diff --git a/src/__tests__/refine.test.ts b/src/__tests__/refine.test.ts index 4d03439ba..0818e422b 100644 --- a/src/__tests__/refine.test.ts +++ b/src/__tests__/refine.test.ts @@ -84,13 +84,15 @@ test("refinement Promise", async () => { }); test("custom path", async () => { - const result = await z - .object({ - password: z.string(), - confirm: z.string(), - }) - .refine((data) => data.confirm === data.password, { path: ["confirm"] }) - .spa({ password: "asdf", confirm: "qewr" }); + const result = await z.spa( + z + .object({ + password: z.string(), + confirm: z.string(), + }) + .refine((data) => data.confirm === data.password, { path: ["confirm"] }), + { password: "asdf", confirm: "qewr" } + ); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].path).toEqual(["confirm"]); @@ -114,8 +116,8 @@ test("use path in refinement context", async () => { foo: noNested, }); - const t1 = await noNested.spa("asdf"); - const t2 = await data.spa({ foo: "asdf" }); + const t1 = await z.spa(noNested, "asdf"); + const t2 = await z.spa(data, { foo: "asdf" }); expect(t1.success).toBe(true); expect(t2.success).toBe(false); @@ -147,7 +149,7 @@ test("superRefine", () => { } }); - const result = Strings.safeParse(["asfd", "asfd", "asfd", "asfd"]); + const result = z.safeParse(Strings, ["asfd", "asfd", "asfd", "asfd"]); expect(result.success).toEqual(false); if (!result.success) expect(result.error.issues.length).toEqual(2); @@ -176,7 +178,12 @@ test("superRefine async", async () => { } }); - const result = await Strings.safeParseAsync(["asfd", "asfd", "asfd", "asfd"]); + const result = await z.safeParseAsync(Strings, [ + "asfd", + "asfd", + "asfd", + "asfd", + ]); expect(result.success).toEqual(false); if (!result.success) expect(result.error.issues.length).toEqual(2); @@ -207,8 +214,8 @@ test("superRefine - type narrowing", () => { util.assertEqual, NarrowType>(true); - expect(schema.safeParse({ type: "test", age: 0 }).success).toEqual(true); - expect(schema.safeParse(null).success).toEqual(false); + expect(z.safeParse(schema, { type: "test", age: 0 }).success).toEqual(true); + expect(z.safeParse(schema, null).success).toEqual(false); }); test("chained mixed refining types", () => { @@ -263,14 +270,14 @@ test("chained refinements", () => { path: ["size"], message: "size greater than 7", }); - const r1 = objectSchema.safeParse({ + const r1 = z.safeParse(objectSchema, { length: 4, size: 9, }); expect(r1.success).toEqual(false); if (!r1.success) expect(r1.error.issues.length).toEqual(1); - const r2 = objectSchema.safeParse({ + const r2 = z.safeParse(objectSchema, { length: 4, size: 3, }); @@ -299,7 +306,7 @@ test("fatal superRefine", () => { } }); - const result = Strings.safeParse(""); + const result = z.safeParse(Strings, ""); expect(result.success).toEqual(false); if (!result.success) expect(result.error.issues.length).toEqual(1); diff --git a/src/__tests__/safeparse.test.ts b/src/__tests__/safeparse.test.ts index e381a1fa1..1d362438d 100644 --- a/src/__tests__/safeparse.test.ts +++ b/src/__tests__/safeparse.test.ts @@ -5,23 +5,24 @@ import * as z from "../index"; const stringSchema = z.string(); test("safeparse fail", () => { - const safe = stringSchema.safeParse(12); + const safe = z.safeParse(stringSchema, 12); expect(safe.success).toEqual(false); expect(safe.error).toBeInstanceOf(z.ZodError); }); test("safeparse pass", () => { - const safe = stringSchema.safeParse("12"); + const safe = z.safeParse(stringSchema, "12"); expect(safe.success).toEqual(true); expect(safe.data).toEqual("12"); }); test("safeparse unexpected error", () => { expect(() => - stringSchema - .refine((data) => { + z.safeParse( + stringSchema.refine((data) => { throw new Error(data); - }) - .safeParse("12") + }), + "12" + ) ).toThrow(); }); diff --git a/src/__tests__/set.test.ts b/src/__tests__/set.test.ts index 5526a4f3a..c4b96afe9 100644 --- a/src/__tests__/set.test.ts +++ b/src/__tests__/set.test.ts @@ -19,7 +19,7 @@ test("type inference", () => { }); test("valid parse", () => { - const result = stringSet.safeParse(new Set(["first", "second"])); + const result = z.safeParse(stringSet, new Set(["first", "second"])); expect(result.success).toEqual(true); if (result.success) { expect(result.data.has("first")).toEqual(true); @@ -39,7 +39,7 @@ test("valid parse", () => { }); test("valid parse async", async () => { - const result = await stringSet.spa(new Set(["first", "second"])); + const result = await z.spa(stringSet, new Set(["first", "second"])); expect(result.success).toEqual(true); if (result.success) { expect(result.data.has("first")).toEqual(true); @@ -47,7 +47,10 @@ test("valid parse async", async () => { expect(result.data.has("third")).toEqual(false); } - const asyncResult = await stringSet.safeParse(new Set(["first", "second"])); + const asyncResult = await z.safeParse( + stringSet, + new Set(["first", "second"]) + ); expect(asyncResult.success).toEqual(true); if (asyncResult.success) { expect(asyncResult.data.has("first")).toEqual(true); @@ -75,7 +78,7 @@ test("valid parse: size-related methods", () => { }); test("failing when parsing empty set in nonempty ", () => { - const result = nonEmpty.safeParse(new Set()); + const result = z.safeParse(nonEmpty, new Set()); expect(result.success).toEqual(false); if (result.success === false) { @@ -85,7 +88,7 @@ test("failing when parsing empty set in nonempty ", () => { }); test("failing when set is smaller than min() ", () => { - const result = minTwo.safeParse(new Set(["just_one"])); + const result = z.safeParse(minTwo, new Set(["just_one"])); expect(result.success).toEqual(false); if (result.success === false) { @@ -95,7 +98,7 @@ test("failing when set is smaller than min() ", () => { }); test("failing when set is bigger than max() ", () => { - const result = maxTwo.safeParse(new Set(["one", "two", "three"])); + const result = z.safeParse(maxTwo, new Set(["one", "two", "three"])); expect(result.success).toEqual(false); if (result.success === false) { @@ -105,12 +108,12 @@ test("failing when set is bigger than max() ", () => { }); test("doesn’t throw when an empty set is given", () => { - const result = stringSet.safeParse(new Set([])); + const result = z.safeParse(stringSet, new Set([])); expect(result.success).toEqual(true); }); test("throws when a Map is given", () => { - const result = stringSet.safeParse(new Map([])); + const result = z.safeParse(stringSet, new Map([])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(1); @@ -119,7 +122,7 @@ test("throws when a Map is given", () => { }); test("throws when the given set has invalid input", () => { - const result = stringSet.safeParse(new Set([Symbol()])); + const result = z.safeParse(stringSet, new Set([Symbol()])); expect(result.success).toEqual(false); if (result.success === false) { expect(result.error.issues.length).toEqual(1); @@ -129,7 +132,7 @@ test("throws when the given set has invalid input", () => { }); test("throws when the given set has multiple invalid entries", () => { - const result = stringSet.safeParse(new Set([1, 2] as any[]) as Set); + const result = z.safeParse(stringSet, new Set([1, 2] as any[]) as Set); expect(result.success).toEqual(false); if (result.success === false) { diff --git a/src/__tests__/string.test.ts b/src/__tests__/string.test.ts index db01a64eb..9c9efd419 100644 --- a/src/__tests__/string.test.ts +++ b/src/__tests__/string.test.ts @@ -154,12 +154,12 @@ test("email validations", () => { expect( validEmails.every((email) => { - return emailSchema.safeParse(email).success; + return z.safeParse(emailSchema, email).success; }) ).toBe(true); expect( invalidEmails.every((email) => { - return emailSchema.safeParse(email).success === false; + return z.safeParse(emailSchema, email).success === false; }) ).toBe(true); }); @@ -179,7 +179,9 @@ test("base64 validations", () => { ]; for (const str of validBase64Strings) { - expect(str + z.string().base64().safeParse(str).success).toBe(str + "true"); + expect(str + z.safeParse(z.string().base64(), str).success).toBe( + str + "true" + ); } const invalidBase64Strings = [ @@ -193,7 +195,7 @@ test("base64 validations", () => { ]; for (const str of invalidBase64Strings) { - expect(str + z.string().base64().safeParse(str).success).toBe( + expect(str + z.safeParse(z.string().base64(), str).success).toBe( str + "false" ); } @@ -250,7 +252,7 @@ test("uuid", () => { uuid.parse("00000000-0000-0000-0000-000000000000"); uuid.parse("b3ce60f8-e8b9-40f5-1150-172ede56ff74"); // Variant 0 - RFC 4122: Reserved, NCS backward compatibility uuid.parse("92e76bf9-28b3-4730-cd7f-cb6bc51f8c09"); // Variant 2 - RFC 4122: Reserved, Microsoft Corporation backward compatibility - const result = uuid.safeParse("9491d710-3185-4e06-bea0-6a2f275345e0X"); + const result = z.safeParse(uuid, "9491d710-3185-4e06-bea0-6a2f275345e0X"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("custom error"); @@ -260,7 +262,7 @@ test("uuid", () => { test("bad uuid", () => { const uuid = z.string().uuid("custom error"); uuid.parse("9491d710-3185-4e06-bea0-6a2f275345e0"); - const result = uuid.safeParse("invalid uuid"); + const result = z.safeParse(uuid, "invalid uuid"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("custom error"); @@ -273,7 +275,7 @@ test("nanoid", () => { nanoid.parse("mIU_4PJWikaU8fMbmkouz"); nanoid.parse("Hb9ZUtUa2JDm_dD-47EGv"); nanoid.parse("5Noocgv_8vQ9oPijj4ioQ"); - const result = nanoid.safeParse("Xq90uDyhddC53KsoASYJGX"); + const result = z.safeParse(nanoid, "Xq90uDyhddC53KsoASYJGX"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("custom error"); @@ -283,7 +285,7 @@ test("nanoid", () => { test("bad nanoid", () => { const nanoid = z.string().nanoid("custom error"); nanoid.parse("ySh_984wpDUu7IQRrLXAp"); - const result = nanoid.safeParse("invalid nanoid"); + const result = z.safeParse(nanoid, "invalid nanoid"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("custom error"); @@ -293,7 +295,7 @@ test("bad nanoid", () => { test("cuid", () => { const cuid = z.string().cuid(); cuid.parse("ckopqwooh000001la8mbi2im9"); - const result = cuid.safeParse("cifjhdsfhsd-invalid-cuid"); + const result = z.safeParse(cuid, "cifjhdsfhsd-invalid-cuid"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("Invalid cuid"); @@ -313,7 +315,7 @@ test("cuid2", () => { "tz4a98xxat96iws9zMbrgj3a", // include uppercase "tz4a98xxat96iws-zmbrgj3a", // involve symbols ]; - const results = invalidStrings.map((s) => cuid2.safeParse(s)); + const results = invalidStrings.map((s) => z.safeParse(cuid2, s)); expect(results.every((r) => !r.success)).toEqual(true); if (!results[0].success) { expect(results[0].error.issues[0].message).toEqual("Invalid cuid2"); @@ -323,10 +325,10 @@ test("cuid2", () => { test("ulid", () => { const ulid = z.string().ulid(); ulid.parse("01ARZ3NDEKTSV4RRFFQ69G5FAV"); - const result = ulid.safeParse("invalidulid"); + const result = z.safeParse(ulid, "invalidulid"); expect(result.success).toEqual(false); const tooLong = "01ARZ3NDEKTSV4RRFFQ69G5FAVA"; - expect(ulid.safeParse(tooLong).success).toEqual(false); + expect(z.safeParse(ulid, tooLong).success).toEqual(false); if (!result.success) { expect(result.error.issues[0].message).toEqual("Invalid ulid"); } @@ -340,10 +342,10 @@ test("regex", () => { }); test("regexp error message", () => { - const result = z + const result = z.safeParse(z .string() .regex(/^moo+$/) - .safeParse("boooo"); + ,"boooo") if (!result.success) { expect(result.error.issues[0].message).toEqual("Invalid"); } else { @@ -355,11 +357,11 @@ test("regexp error message", () => { test("regex lastIndex reset", () => { const schema = z.string().regex(/^\d+$/g); - expect(schema.safeParse("123").success).toEqual(true); - expect(schema.safeParse("123").success).toEqual(true); - expect(schema.safeParse("123").success).toEqual(true); - expect(schema.safeParse("123").success).toEqual(true); - expect(schema.safeParse("123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); + expect(z.safeParse(schema, "123").success).toEqual(true); }); test("checks getters", () => { @@ -707,14 +709,14 @@ test("duration", () => { ]; for (const val of validDurations) { - const result = duration.safeParse(val); + const result = z.safeParse(duration, val); if (!result.success) { throw Error(`Valid duration could not be parsed: ${val}`); } } for (const val of invalidDurations) { - const result = duration.safeParse(val); + const result = z.safeParse(duration, val); if (result.success) { throw Error(`Invalid duration was successful parsed: ${val}`); @@ -726,7 +728,7 @@ test("duration", () => { test("IP validation", () => { const ip = z.string().ip(); - expect(ip.safeParse("122.122.122.122").success).toBe(true); + expect(z.safeParse(ip, "122.122.122.122").success).toBe(true); const ipv4 = z.string().ip({ version: "v4" }); expect(() => ipv4.parse("6097:adfa:6f0b:220d:db08:5021:6191:7990")).toThrow(); @@ -759,8 +761,8 @@ test("IP validation", () => { ]; // no parameters check IPv4 or IPv6 const ipSchema = z.string().ip(); - expect(validIPs.every((ip) => ipSchema.safeParse(ip).success)).toBe(true); + expect(validIPs.every((ip) => z.safeParse(ipSchema, ip).success)).toBe(true); expect( - invalidIPs.every((ip) => ipSchema.safeParse(ip).success === false) + invalidIPs.every((ip) => z.safeParse(ipSchema, ip).success === false) ).toBe(true); }); diff --git a/src/__tests__/transformer.test.ts b/src/__tests__/transformer.test.ts index 0f80aa030..cdf5d72c1 100644 --- a/src/__tests__/transformer.test.ts +++ b/src/__tests__/transformer.test.ts @@ -44,9 +44,8 @@ test("transform ctx.addIssue with parse", () => { test("transform ctx.addIssue with parseAsync", async () => { const strs = ["foo", "bar"]; - const result = await z - .string() - .transform(async (data, ctx) => { + const result = await z.safeParseAsync( + z.string().transform(async (data, ctx) => { const i = strs.indexOf(data); if (i === -1) { ctx.addIssue({ @@ -55,8 +54,9 @@ test("transform ctx.addIssue with parseAsync", async () => { }); } return data.length; - }) - .safeParseAsync("asdf"); + }), + "asdf" + ); expect(JSON.parse(JSON.stringify(result))).toEqual({ success: false, @@ -86,7 +86,7 @@ test("z.NEVER in transform", () => { }); type foo = z.infer; util.assertEqual(true); - const arg = foo.safeParse(undefined); + const arg = z.safeParse(foo, undefined); if (!arg.success) { expect(arg.error.issues[0].message).toEqual("bad"); } @@ -201,13 +201,13 @@ test("short circuit on dirty", () => { .string() .refine(() => false) .transform((val) => val.toUpperCase()); - const result = schema.safeParse("asdf"); + const result = z.safeParse(schema, "asdf"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.custom); } - const result2 = schema.safeParse(1234); + const result2 = z.safeParse(schema, 1234); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_type); @@ -219,13 +219,13 @@ test("async short circuit on dirty", async () => { .string() .refine(() => false) .transform((val) => val.toUpperCase()); - const result = await schema.spa("asdf"); + const result = await z.spa(schema, "asdf"); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.custom); } - const result2 = await schema.spa(1234); + const result2 = await z.spa(schema, 1234); expect(result2.success).toEqual(false); if (!result2.success) { expect(result2.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_type); diff --git a/src/__tests__/tuple.test.ts b/src/__tests__/tuple.test.ts index 364881c4e..7a484fce3 100644 --- a/src/__tests__/tuple.test.ts +++ b/src/__tests__/tuple.test.ts @@ -45,7 +45,7 @@ test("failed validation", () => { }); test("failed async validation", async () => { - const res = await testTuple.safeParse(badData); + const res = await z.safeParse(testTuple, badData); expect(res.success).toEqual(false); if (!res.success) { expect(res.error.issues.length).toEqual(3); diff --git a/src/__tests__/unions.test.ts b/src/__tests__/unions.test.ts index e7b30bcef..02fb15bb3 100644 --- a/src/__tests__/unions.test.ts +++ b/src/__tests__/unions.test.ts @@ -8,14 +8,15 @@ test("function parsing", () => { z.string().refine(() => false), z.number().refine(() => false), ]); - const result = schema.safeParse("asdf"); + const result = z.safeParse(schema, "asdf"); expect(result.success).toEqual(false); }); test("union 2", () => { - const result = z - .union([z.number(), z.string().refine(() => false)]) - .safeParse("a"); + const result = z.safeParse( + z.union([z.number(), z.string().refine(() => false)]), + "a" + ); expect(result.success).toEqual(false); }); @@ -33,9 +34,10 @@ test("return valid over invalid", () => { }); test("return dirty result over aborted", () => { - const result = z - .union([z.number(), z.string().refine(() => false)]) - .safeParse("a"); + const result = z.safeParse( + z.union([z.number(), z.string().refine(() => false)]), + "a" + ); expect(result.success).toEqual(false); if (!result.success) { expect(result.error.issues).toEqual([ diff --git a/src/types.ts b/src/types.ts index 6873f05a9..f9d96eeb9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5242,24 +5242,15 @@ export async function safeParseAsync( /** Alias of safeParseAsync */ export const spa = safeParseAsync; -export function catch_< - Output, - Input, - Schema extends ZodType ->(schema: Schema, def: Output): ZodCatch; -export function catch_< - Output, - Input, - Schema extends ZodType ->( +export function catch_( schema: Schema, - def: (ctx: { error: ZodError; input: Input }) => Output + def: output ): ZodCatch; -export function catch_< - Output, - Input, - Schema extends ZodType ->(schema: Schema, def: any) { +export function catch_( + schema: Schema, + def: (ctx: { error: ZodError; input: input }) => output +): ZodCatch; +export function catch_(schema: Schema, def: any) { const catchValueFunc = typeof def === "function" ? def : () => def; return new ZodCatch({ From f9ca8b0920eb00659ac4f759e20e2cea613b4ff0 Mon Sep 17 00:00:00 2001 From: Kartal Kaan Bozdogan Date: Sat, 12 Oct 2024 23:14:15 +0200 Subject: [PATCH 4/6] Added new covariance/contravariance tests --- deno/lib/__tests__/type.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 deno/lib/__tests__/type.test.ts diff --git a/deno/lib/__tests__/type.test.ts b/deno/lib/__tests__/type.test.ts new file mode 100644 index 000000000..84cf43cb1 --- /dev/null +++ b/deno/lib/__tests__/type.test.ts @@ -0,0 +1,14 @@ +import { expect } from "https://deno.land/x/expect@v0.2.6/mod.ts"; +const test = Deno.test; + +import * as z from "../index.ts"; + +test("ZodType is covariant with the output", () => { + function f>(_: S) {} + f(z.literal("a")); +}); + +test("ZodType is contravariant with the input", () => { + function f>(_: S) {} + f(z.string()); +}); From 304c024ebe97fbc33054b398471783ee9c9ee7d6 Mon Sep 17 00:00:00 2001 From: Kartal Kaan Bozdogan Date: Sat, 12 Oct 2024 23:21:50 +0200 Subject: [PATCH 5/6] Added new tests for covariance on the output and contravariance on the input --- deno/lib/__tests__/type.test.ts | 8 ++++++++ src/__tests__/type.test.ts | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/__tests__/type.test.ts diff --git a/deno/lib/__tests__/type.test.ts b/deno/lib/__tests__/type.test.ts index 84cf43cb1..075481ea8 100644 --- a/deno/lib/__tests__/type.test.ts +++ b/deno/lib/__tests__/type.test.ts @@ -6,9 +6,17 @@ import * as z from "../index.ts"; test("ZodType is covariant with the output", () => { function f>(_: S) {} f(z.literal("a")); + + function g>(_: S) {} + // @ts-expect-error + g(z.string()); }); test("ZodType is contravariant with the input", () => { function f>(_: S) {} f(z.string()); + + function g>(_: S) {} + // @ts-expect-error + g(z.literal("a")); }); diff --git a/src/__tests__/type.test.ts b/src/__tests__/type.test.ts new file mode 100644 index 000000000..dfef3f6a7 --- /dev/null +++ b/src/__tests__/type.test.ts @@ -0,0 +1,21 @@ +import { test } from "@jest/globals"; + +import * as z from "../index"; + +test("ZodType is covariant with the output", () => { + function f>(_: S) {} + f(z.literal("a")); + + function g>(_: S) {} + // @ts-expect-error + g(z.string()); +}); + +test("ZodType is contravariant with the input", () => { + function f>(_: S) {} + f(z.string()); + + function g>(_: S) {} + // @ts-expect-error + g(z.literal("a")); +}); From 994a243f7f45ab0feb26532b7f5104ce146c7e1c Mon Sep 17 00:00:00 2001 From: Kartal Kaan Bozdogan Date: Sun, 13 Oct 2024 13:37:10 +0200 Subject: [PATCH 6/6] Fix more tests --- deno/lib/helpers/partialUtil.ts | 47 ++++++++++++++++----------------- deno/lib/types.ts | 20 +++++++------- src/helpers/partialUtil.ts | 47 ++++++++++++++++----------------- src/types.ts | 20 +++++++------- 4 files changed, 64 insertions(+), 70 deletions(-) diff --git a/deno/lib/helpers/partialUtil.ts b/deno/lib/helpers/partialUtil.ts index b9de239fd..be41eb74a 100644 --- a/deno/lib/helpers/partialUtil.ts +++ b/deno/lib/helpers/partialUtil.ts @@ -1,9 +1,9 @@ import type { + AnyZodObject, ZodArray, ZodNullable, ZodObject, ZodOptional, - ZodRawShape, ZodTuple, ZodTupleItems, ZodTypeAny, @@ -35,30 +35,29 @@ export namespace partialUtil { // ? "object" // T extends ZodOptional // ? 'optional' // : // : "rest"]; - export type DeepPartial = - T extends ZodObject - ? ZodObject< - { [k in keyof T["shape"]]: ZodOptional> }, - T["_def"]["unknownKeys"], - T["_def"]["catchall"] - > - : T extends ZodArray - ? ZodArray, Card> - : T extends ZodOptional - ? ZodOptional> - : T extends ZodNullable - ? ZodNullable> - : T extends ZodTuple - ? { - [k in keyof Items]: Items[k] extends ZodTypeAny - ? DeepPartial - : never; - } extends infer PI - ? PI extends ZodTupleItems - ? ZodTuple - : never + export type DeepPartial = T extends AnyZodObject + ? ZodObject< + { [k in keyof T["shape"]]: ZodOptional> }, + T["_def"]["unknownKeys"], + T["_def"]["catchall"] + > + : T extends ZodArray + ? ZodArray, Card> + : T extends ZodOptional + ? ZodOptional> + : T extends ZodNullable + ? ZodNullable> + : T extends ZodTuple + ? { + [k in keyof Items]: Items[k] extends ZodTypeAny + ? DeepPartial + : never; + } extends infer PI + ? PI extends ZodTupleItems + ? ZodTuple : never - : T; + : never + : T; // { // // optional: T extends ZodOptional ? T : ZodOptional; // // array: T extends ZodArray ? ZodArray> : never; diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 59d82fdb4..17b80d604 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -2839,7 +2839,7 @@ export class ZodObject< }; } -export type AnyZodObject = ZodObject; +export type AnyZodObject = ZodObject; //////////////////////////////////////// //////////////////////////////////////// @@ -3347,17 +3347,15 @@ export interface ZodTupleDef< typeName: ZodFirstPartyTypeKind.ZodTuple; } -export type AnyZodTuple = ZodTuple< - [ZodTypeAny, ...ZodTypeAny[]] | [], - ZodTypeAny | null ->; +export type AnyZodTuple = ZodTuple<[] | ZodTupleItems, any, any | never>; export class ZodTuple< T extends [ZodTypeAny, ...ZodTypeAny[]] | [] = [ZodTypeAny, ...ZodTypeAny[]], - Rest extends ZodTypeAny | null = null + Rest extends ZodTypeAny | null = null, + Input = InputTypeOfTupleWithRest > extends ZodType< OutputTypeOfTupleWithRest, ZodTupleDef, - InputTypeOfTupleWithRest + Input > { _parse(input: ParseInput): ParseReturnType { const { status, ctx } = this._processInputParams(input); @@ -3788,7 +3786,7 @@ export class ZodSet extends ZodType< /////////////////////////////////////////// /////////////////////////////////////////// export interface ZodFunctionDef< - Args extends ZodTuple = ZodTuple, + Args extends AnyZodTuple = AnyZodTuple, Returns extends ZodTypeAny = ZodTypeAny > extends ZodTypeDef { args: Args; @@ -3797,21 +3795,21 @@ export interface ZodFunctionDef< } export type OuterTypeOfFunction< - Args extends ZodTuple, + Args extends AnyZodTuple, Returns extends ZodTypeAny > = input extends Array ? (...args: input) => Returns["_output"] : never; export type InnerTypeOfFunction< - Args extends ZodTuple, + Args extends AnyZodTuple, Returns extends ZodTypeAny > = Args["_output"] extends Array ? (...args: Args["_output"]) => input : never; export class ZodFunction< - Args extends ZodTuple, + Args extends AnyZodTuple, Returns extends ZodTypeAny > extends ZodType< OuterTypeOfFunction, diff --git a/src/helpers/partialUtil.ts b/src/helpers/partialUtil.ts index ebfa5ec31..23aa988ac 100644 --- a/src/helpers/partialUtil.ts +++ b/src/helpers/partialUtil.ts @@ -1,9 +1,9 @@ import type { + AnyZodObject, ZodArray, ZodNullable, ZodObject, ZodOptional, - ZodRawShape, ZodTuple, ZodTupleItems, ZodTypeAny, @@ -35,30 +35,29 @@ export namespace partialUtil { // ? "object" // T extends ZodOptional // ? 'optional' // : // : "rest"]; - export type DeepPartial = - T extends ZodObject - ? ZodObject< - { [k in keyof T["shape"]]: ZodOptional> }, - T["_def"]["unknownKeys"], - T["_def"]["catchall"] - > - : T extends ZodArray - ? ZodArray, Card> - : T extends ZodOptional - ? ZodOptional> - : T extends ZodNullable - ? ZodNullable> - : T extends ZodTuple - ? { - [k in keyof Items]: Items[k] extends ZodTypeAny - ? DeepPartial - : never; - } extends infer PI - ? PI extends ZodTupleItems - ? ZodTuple - : never + export type DeepPartial = T extends AnyZodObject + ? ZodObject< + { [k in keyof T["shape"]]: ZodOptional> }, + T["_def"]["unknownKeys"], + T["_def"]["catchall"] + > + : T extends ZodArray + ? ZodArray, Card> + : T extends ZodOptional + ? ZodOptional> + : T extends ZodNullable + ? ZodNullable> + : T extends ZodTuple + ? { + [k in keyof Items]: Items[k] extends ZodTypeAny + ? DeepPartial + : never; + } extends infer PI + ? PI extends ZodTupleItems + ? ZodTuple : never - : T; + : never + : T; // { // // optional: T extends ZodOptional ? T : ZodOptional; // // array: T extends ZodArray ? ZodArray> : never; diff --git a/src/types.ts b/src/types.ts index f9d96eeb9..84a0f0197 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2839,7 +2839,7 @@ export class ZodObject< }; } -export type AnyZodObject = ZodObject; +export type AnyZodObject = ZodObject; //////////////////////////////////////// //////////////////////////////////////// @@ -3347,17 +3347,15 @@ export interface ZodTupleDef< typeName: ZodFirstPartyTypeKind.ZodTuple; } -export type AnyZodTuple = ZodTuple< - [ZodTypeAny, ...ZodTypeAny[]] | [], - ZodTypeAny | null ->; +export type AnyZodTuple = ZodTuple<[] | ZodTupleItems, any, any | never>; export class ZodTuple< T extends [ZodTypeAny, ...ZodTypeAny[]] | [] = [ZodTypeAny, ...ZodTypeAny[]], - Rest extends ZodTypeAny | null = null + Rest extends ZodTypeAny | null = null, + Input = InputTypeOfTupleWithRest > extends ZodType< OutputTypeOfTupleWithRest, ZodTupleDef, - InputTypeOfTupleWithRest + Input > { _parse(input: ParseInput): ParseReturnType { const { status, ctx } = this._processInputParams(input); @@ -3788,7 +3786,7 @@ export class ZodSet extends ZodType< /////////////////////////////////////////// /////////////////////////////////////////// export interface ZodFunctionDef< - Args extends ZodTuple = ZodTuple, + Args extends AnyZodTuple = AnyZodTuple, Returns extends ZodTypeAny = ZodTypeAny > extends ZodTypeDef { args: Args; @@ -3797,21 +3795,21 @@ export interface ZodFunctionDef< } export type OuterTypeOfFunction< - Args extends ZodTuple, + Args extends AnyZodTuple, Returns extends ZodTypeAny > = input extends Array ? (...args: input) => Returns["_output"] : never; export type InnerTypeOfFunction< - Args extends ZodTuple, + Args extends AnyZodTuple, Returns extends ZodTypeAny > = Args["_output"] extends Array ? (...args: Args["_output"]) => input : never; export class ZodFunction< - Args extends ZodTuple, + Args extends AnyZodTuple, Returns extends ZodTypeAny > extends ZodType< OuterTypeOfFunction,