From d3ddd3ae3686ec64f8ae5c22316f85da8e3bc6a2 Mon Sep 17 00:00:00 2001 From: santosmarco Date: Sat, 24 Dec 2022 19:37:54 -0300 Subject: [PATCH 1/2] Fix passing params in root class --- deno/lib/README.md | 30 +++++++++++++++--------------- deno/lib/types.ts | 21 ++++++++++++--------- src/types.ts | 17 ++++++++++------- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/deno/lib/README.md b/deno/lib/README.md index b502de431..9e03d7fe4 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -47,8 +47,9 @@ - [Sponsors](#sponsors) - [Ecosystem](#ecosystem) - [Installation](#installation) - - [Node/npm](#nodenpm) - - [Deno](#deno) + - [Requirements](#requirements) + - [Node/npm](#from-npm-nodebun) + - [Deno](#from-denolandx-deno) - [Basic usage](#basic-usage) - [Primitives](#primitives) - [Literals](#literals) @@ -1294,7 +1295,7 @@ const myUnion = z.discriminatedUnion("status", [ z.object({ status: z.literal("failed"), error: z.instanceof(Error) }), ]); -myUnion.parse({ type: "success", data: "yippie ki yay" }); +myUnion.parse({ status: "success", data: "yippie ki yay" }); ``` ## Records @@ -1682,7 +1683,7 @@ Given any Zod schema, you can call its `.parse` method to check `data` is valid. const stringSchema = z.string(); stringSchema.parse("fish"); // => returns "fish" -stringSchema.parse(12); // throws Error('Non-string type: number'); +stringSchema.parse(12); // throws error ``` ### `.parseAsync` @@ -1692,11 +1693,10 @@ stringSchema.parse(12); // throws Error('Non-string type: number'); If you use asynchronous [refinements](#refine) or [transforms](#transform) (more on those later), you'll need to use `.parseAsync` ```ts -const stringSchema1 = z.string().refine(async (val) => val.length < 20); -const value1 = await stringSchema.parseAsync("hello"); // => hello +const stringSchema = z.string().refine(async (val) => val.length <= 8); -const stringSchema2 = z.string().refine(async (val) => val.length > 20); -const value2 = await stringSchema.parseAsync("hello"); // => throws +await stringSchema.parseAsync("hello"); // => returns "hello" +await stringSchema.parseAsync("hello world"); // => throws error ``` ### `.safeParse` @@ -1781,7 +1781,7 @@ type RefineParams = { }; ``` -For advanced cases, the second argument can also be a function that returns `RefineParams`/ +For advanced cases, the second argument can also be a function that returns `RefineParams`. ```ts const longString = z.string().refine( @@ -1921,7 +1921,7 @@ const schema = z.number().superRefine((val, ctx) => { #### Type refinements -If you provide a [type predicate](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) to `.refine()` or `superRefine()`, the resulting type will be narrowed down to your predicate's type. This is useful if you are mixing multiple chained refinements and transformations: +If you provide a [type predicate](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) to `.refine()` or `.superRefine()`, the resulting type will be narrowed down to your predicate's type. This is useful if you are mixing multiple chained refinements and transformations: ```ts const schema = z @@ -1936,15 +1936,15 @@ const schema = z code: z.ZodIssueCode.custom, // customize your issue message: "object should exist", }); - return false; } - return true; + + return z.NEVER; // The return value is not used, but we need to return something to satisfy the typing }) // here, TS knows that arg is not null .refine((arg) => arg.first === "bob", "`first` is not `bob`!"); ``` -> ⚠️ You must **still** call `ctx.addIssue()` if using `superRefine()` with a type predicate function. Otherwise the refinement won't be validated. +> ⚠️ You **must** use `ctx.addIssue()` instead of returning a boolean value to indicate whether the validation passes. If `ctx.addIssue` is _not_ called during the execution of the function, validation passes. ### `.transform` @@ -1971,12 +1971,12 @@ emailToDomain.parse("colinhacks@example.com"); // => example.com #### Validating during transform -The `.transform` method can simultaneously validate and transform the value. This is often simpler and less duplicative than chaining `refine` and `validate`. +The `.transform` method can simultaneously validate and transform the value. This is often simpler and less duplicative than chaining `transform` and `refine`. As with `.superRefine`, the transform function receives a `ctx` object with a `addIssue` method that can be used to register validation issues. ```ts -const Strings = z.string().transform((val, ctx) => { +const numberInString = z.string().transform((val, ctx) => { const parsed = parseInt(val); if (isNaN(parsed)) { ctx.addIssue({ diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 895da711f..2a1c66085 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -390,33 +390,34 @@ export abstract class ZodType< } optional(): ZodOptional { - return ZodOptional.create(this) as any; + return ZodOptional.create(this, this._def) as any; } nullable(): ZodNullable { - return ZodNullable.create(this) as any; + return ZodNullable.create(this, this._def) as any; } nullish(): ZodNullable> { return this.optional().nullable(); } array(): ZodArray { - return ZodArray.create(this); + return ZodArray.create(this, this._def); } promise(): ZodPromise { - return ZodPromise.create(this); + return ZodPromise.create(this, this._def); } or(option: T): ZodUnion<[this, T]> { - return ZodUnion.create([this, option]) as any; + return ZodUnion.create([this, option], this._def) as any; } and(incoming: T): ZodIntersection { - return ZodIntersection.create(this, incoming); + return ZodIntersection.create(this, incoming, this._def); } transform( transform: (arg: Output, ctx: RefinementCtx) => NewOut | Promise ): ZodEffects { return new ZodEffects({ + ...processCreateParams(this._def), schema: this, typeName: ZodFirstPartyTypeKind.ZodEffects, effect: { type: "transform", transform }, @@ -429,6 +430,7 @@ export abstract class ZodType< const defaultValueFunc = typeof def === "function" ? def : () => def; return new ZodDefault({ + ...processCreateParams(this._def), innerType: this, defaultValue: defaultValueFunc, typeName: ZodFirstPartyTypeKind.ZodDefault, @@ -440,7 +442,7 @@ export abstract class ZodType< return new ZodBranded({ typeName: ZodFirstPartyTypeKind.ZodBranded, type: this, - ...processCreateParams(undefined), + ...processCreateParams(this._def), }); } @@ -450,6 +452,7 @@ export abstract class ZodType< const catchValueFunc = typeof def === "function" ? def : () => def; return new ZodCatch({ + ...processCreateParams(this._def), innerType: this, catchValue: catchValueFunc, typeName: ZodFirstPartyTypeKind.ZodCatch, @@ -1713,7 +1716,7 @@ export class ZodArray< if (ctx.common.async) { return Promise.all( - (ctx.data as any[]).map((item, i) => { + ([...ctx.data] as any[]).map((item, i) => { return def.type._parseAsync( new ParseInputLazyPath(ctx, item, ctx.path, i) ); @@ -1723,7 +1726,7 @@ export class ZodArray< }); } - const result = (ctx.data as any[]).map((item, i) => { + const result = ([...ctx.data] as any[]).map((item, i) => { return def.type._parseSync( new ParseInputLazyPath(ctx, item, ctx.path, i) ); diff --git a/src/types.ts b/src/types.ts index b26982250..87dd07777 100644 --- a/src/types.ts +++ b/src/types.ts @@ -390,33 +390,34 @@ export abstract class ZodType< } optional(): ZodOptional { - return ZodOptional.create(this) as any; + return ZodOptional.create(this, this._def) as any; } nullable(): ZodNullable { - return ZodNullable.create(this) as any; + return ZodNullable.create(this, this._def) as any; } nullish(): ZodNullable> { return this.optional().nullable(); } array(): ZodArray { - return ZodArray.create(this); + return ZodArray.create(this, this._def); } promise(): ZodPromise { - return ZodPromise.create(this); + return ZodPromise.create(this, this._def); } or(option: T): ZodUnion<[this, T]> { - return ZodUnion.create([this, option]) as any; + return ZodUnion.create([this, option], this._def) as any; } and(incoming: T): ZodIntersection { - return ZodIntersection.create(this, incoming); + return ZodIntersection.create(this, incoming, this._def); } transform( transform: (arg: Output, ctx: RefinementCtx) => NewOut | Promise ): ZodEffects { return new ZodEffects({ + ...processCreateParams(this._def), schema: this, typeName: ZodFirstPartyTypeKind.ZodEffects, effect: { type: "transform", transform }, @@ -429,6 +430,7 @@ export abstract class ZodType< const defaultValueFunc = typeof def === "function" ? def : () => def; return new ZodDefault({ + ...processCreateParams(this._def), innerType: this, defaultValue: defaultValueFunc, typeName: ZodFirstPartyTypeKind.ZodDefault, @@ -440,7 +442,7 @@ export abstract class ZodType< return new ZodBranded({ typeName: ZodFirstPartyTypeKind.ZodBranded, type: this, - ...processCreateParams(undefined), + ...processCreateParams(this._def), }); } @@ -450,6 +452,7 @@ export abstract class ZodType< const catchValueFunc = typeof def === "function" ? def : () => def; return new ZodCatch({ + ...processCreateParams(this._def), innerType: this, catchValue: catchValueFunc, typeName: ZodFirstPartyTypeKind.ZodCatch, From b02b6b18f9752f9a61c0a470c4aa54c9241c8314 Mon Sep 17 00:00:00 2001 From: Jacob Weisenburger <31667350+JacobWeisenburger@users.noreply.github.com> Date: Sat, 31 Dec 2022 09:30:47 -0600 Subject: [PATCH 2/2] Reverted deno/lib/README.md --- deno/lib/README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/deno/lib/README.md b/deno/lib/README.md index 9e03d7fe4..b502de431 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -47,9 +47,8 @@ - [Sponsors](#sponsors) - [Ecosystem](#ecosystem) - [Installation](#installation) - - [Requirements](#requirements) - - [Node/npm](#from-npm-nodebun) - - [Deno](#from-denolandx-deno) + - [Node/npm](#nodenpm) + - [Deno](#deno) - [Basic usage](#basic-usage) - [Primitives](#primitives) - [Literals](#literals) @@ -1295,7 +1294,7 @@ const myUnion = z.discriminatedUnion("status", [ z.object({ status: z.literal("failed"), error: z.instanceof(Error) }), ]); -myUnion.parse({ status: "success", data: "yippie ki yay" }); +myUnion.parse({ type: "success", data: "yippie ki yay" }); ``` ## Records @@ -1683,7 +1682,7 @@ Given any Zod schema, you can call its `.parse` method to check `data` is valid. const stringSchema = z.string(); stringSchema.parse("fish"); // => returns "fish" -stringSchema.parse(12); // throws error +stringSchema.parse(12); // throws Error('Non-string type: number'); ``` ### `.parseAsync` @@ -1693,10 +1692,11 @@ stringSchema.parse(12); // throws error If you use asynchronous [refinements](#refine) or [transforms](#transform) (more on those later), you'll need to use `.parseAsync` ```ts -const stringSchema = z.string().refine(async (val) => val.length <= 8); +const stringSchema1 = z.string().refine(async (val) => val.length < 20); +const value1 = await stringSchema.parseAsync("hello"); // => hello -await stringSchema.parseAsync("hello"); // => returns "hello" -await stringSchema.parseAsync("hello world"); // => throws error +const stringSchema2 = z.string().refine(async (val) => val.length > 20); +const value2 = await stringSchema.parseAsync("hello"); // => throws ``` ### `.safeParse` @@ -1781,7 +1781,7 @@ type RefineParams = { }; ``` -For advanced cases, the second argument can also be a function that returns `RefineParams`. +For advanced cases, the second argument can also be a function that returns `RefineParams`/ ```ts const longString = z.string().refine( @@ -1921,7 +1921,7 @@ const schema = z.number().superRefine((val, ctx) => { #### Type refinements -If you provide a [type predicate](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) to `.refine()` or `.superRefine()`, the resulting type will be narrowed down to your predicate's type. This is useful if you are mixing multiple chained refinements and transformations: +If you provide a [type predicate](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) to `.refine()` or `superRefine()`, the resulting type will be narrowed down to your predicate's type. This is useful if you are mixing multiple chained refinements and transformations: ```ts const schema = z @@ -1936,15 +1936,15 @@ const schema = z code: z.ZodIssueCode.custom, // customize your issue message: "object should exist", }); + return false; } - - return z.NEVER; // The return value is not used, but we need to return something to satisfy the typing + return true; }) // here, TS knows that arg is not null .refine((arg) => arg.first === "bob", "`first` is not `bob`!"); ``` -> ⚠️ You **must** use `ctx.addIssue()` instead of returning a boolean value to indicate whether the validation passes. If `ctx.addIssue` is _not_ called during the execution of the function, validation passes. +> ⚠️ You must **still** call `ctx.addIssue()` if using `superRefine()` with a type predicate function. Otherwise the refinement won't be validated. ### `.transform` @@ -1971,12 +1971,12 @@ emailToDomain.parse("colinhacks@example.com"); // => example.com #### Validating during transform -The `.transform` method can simultaneously validate and transform the value. This is often simpler and less duplicative than chaining `transform` and `refine`. +The `.transform` method can simultaneously validate and transform the value. This is often simpler and less duplicative than chaining `refine` and `validate`. As with `.superRefine`, the transform function receives a `ctx` object with a `addIssue` method that can be used to register validation issues. ```ts -const numberInString = z.string().transform((val, ctx) => { +const Strings = z.string().transform((val, ctx) => { const parsed = parseInt(val); if (isNaN(parsed)) { ctx.addIssue({