From a94294caaaacdd19b0454919835d3b8bc37742e6 Mon Sep 17 00:00:00 2001 From: samchungy Date: Tue, 15 Aug 2023 23:55:22 +1000 Subject: [PATCH 1/5] Upgrade array types --- deno/lib/__tests__/array.test.ts | 2 +- deno/lib/types.ts | 45 +++++++++++++++++++++++--------- src/__tests__/array.test.ts | 2 +- src/types.ts | 45 +++++++++++++++++++++++--------- 4 files changed, 66 insertions(+), 28 deletions(-) diff --git a/deno/lib/__tests__/array.test.ts b/deno/lib/__tests__/array.test.ts index 8aed9d63f..e595bfb50 100644 --- a/deno/lib/__tests__/array.test.ts +++ b/deno/lib/__tests__/array.test.ts @@ -15,7 +15,7 @@ type t1 = z.infer; util.assertEqual<[string, ...string[]], t1>(true); type t2 = z.infer; -util.assertEqual(true); +util.assertEqual<[string, string, ...string[]], t2>(true); test("passing validations", () => { minTwo.parse(["a", "a"]); diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 0740927fa..0416cf0ff 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -1974,22 +1974,35 @@ export interface ZodArrayDef maxLength: { value: number; message?: string } | null; } -export type ArrayCardinality = "many" | "atleastone"; +export type ArrayCardinality = "many" | "atleast" | "exactly"; + +type Tuple = R["length"] extends N + ? R + : Tuple; + +type MinArray = [...Tuple, ...T[]]; + export type arrayOutputType< T extends ZodTypeAny, - Cardinality extends ArrayCardinality = "many" -> = Cardinality extends "atleastone" - ? [T["_output"], ...T["_output"][]] + Cardinality extends ArrayCardinality = "many", + CardinalityAmount extends number = 0 +> = Cardinality extends "atleast" + ? MinArray + : Cardinality extends "exactly" + ? Tuple : T["_output"][]; export class ZodArray< T extends ZodTypeAny, - Cardinality extends ArrayCardinality = "many" + Cardinality extends ArrayCardinality = "many", + CardinalityAmount extends number = 0 > extends ZodType< - arrayOutputType, + arrayOutputType, ZodArrayDef, - Cardinality extends "atleastone" - ? [T["_input"], ...T["_input"][]] + Cardinality extends "atleast" + ? MinArray + : Cardinality extends "exactly" + ? Tuple : T["_input"][] > { _parse(input: ParseInput): ParseReturnType { @@ -2076,28 +2089,34 @@ export class ZodArray< return this._def.type; } - min(minLength: number, message?: errorUtil.ErrMessage): this { + min( + minLength: N, + message?: errorUtil.ErrMessage + ): ZodArray { return new ZodArray({ ...this._def, minLength: { value: minLength, message: errorUtil.toString(message) }, }) as any; } - max(maxLength: number, message?: errorUtil.ErrMessage): this { + max(maxLength: N, message?: errorUtil.ErrMessage): this { return new ZodArray({ ...this._def, maxLength: { value: maxLength, message: errorUtil.toString(message) }, }) as any; } - length(len: number, message?: errorUtil.ErrMessage): this { + length( + len: N, + message?: errorUtil.ErrMessage + ): ZodArray { return new ZodArray({ ...this._def, exactLength: { value: len, message: errorUtil.toString(message) }, }) as any; } - nonempty(message?: errorUtil.ErrMessage): ZodArray { + nonempty(message?: errorUtil.ErrMessage): ZodArray { return this.min(1, message) as any; } @@ -2116,7 +2135,7 @@ export class ZodArray< }; } -export type ZodNonEmptyArray = ZodArray; +export type ZodNonEmptyArray = ZodArray; ///////////////////////////////////////// ///////////////////////////////////////// diff --git a/src/__tests__/array.test.ts b/src/__tests__/array.test.ts index 21ae44bee..94ee5ac01 100644 --- a/src/__tests__/array.test.ts +++ b/src/__tests__/array.test.ts @@ -14,7 +14,7 @@ type t1 = z.infer; util.assertEqual<[string, ...string[]], t1>(true); type t2 = z.infer; -util.assertEqual(true); +util.assertEqual<[string, string, ...string[]], t2>(true); test("passing validations", () => { minTwo.parse(["a", "a"]); diff --git a/src/types.ts b/src/types.ts index 81a5e9f8a..8af0827d3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1974,22 +1974,35 @@ export interface ZodArrayDef maxLength: { value: number; message?: string } | null; } -export type ArrayCardinality = "many" | "atleastone"; +export type ArrayCardinality = "many" | "atleast" | "exactly"; + +type Tuple = R["length"] extends N + ? R + : Tuple; + +type MinArray = [...Tuple, ...T[]]; + export type arrayOutputType< T extends ZodTypeAny, - Cardinality extends ArrayCardinality = "many" -> = Cardinality extends "atleastone" - ? [T["_output"], ...T["_output"][]] + Cardinality extends ArrayCardinality = "many", + CardinalityAmount extends number = 0 +> = Cardinality extends "atleast" + ? MinArray + : Cardinality extends "exactly" + ? Tuple : T["_output"][]; export class ZodArray< T extends ZodTypeAny, - Cardinality extends ArrayCardinality = "many" + Cardinality extends ArrayCardinality = "many", + CardinalityAmount extends number = 0 > extends ZodType< - arrayOutputType, + arrayOutputType, ZodArrayDef, - Cardinality extends "atleastone" - ? [T["_input"], ...T["_input"][]] + Cardinality extends "atleast" + ? MinArray + : Cardinality extends "exactly" + ? Tuple : T["_input"][] > { _parse(input: ParseInput): ParseReturnType { @@ -2076,28 +2089,34 @@ export class ZodArray< return this._def.type; } - min(minLength: number, message?: errorUtil.ErrMessage): this { + min( + minLength: N, + message?: errorUtil.ErrMessage + ): ZodArray { return new ZodArray({ ...this._def, minLength: { value: minLength, message: errorUtil.toString(message) }, }) as any; } - max(maxLength: number, message?: errorUtil.ErrMessage): this { + max(maxLength: N, message?: errorUtil.ErrMessage): this { return new ZodArray({ ...this._def, maxLength: { value: maxLength, message: errorUtil.toString(message) }, }) as any; } - length(len: number, message?: errorUtil.ErrMessage): this { + length( + len: N, + message?: errorUtil.ErrMessage + ): ZodArray { return new ZodArray({ ...this._def, exactLength: { value: len, message: errorUtil.toString(message) }, }) as any; } - nonempty(message?: errorUtil.ErrMessage): ZodArray { + nonempty(message?: errorUtil.ErrMessage): ZodArray { return this.min(1, message) as any; } @@ -2116,7 +2135,7 @@ export class ZodArray< }; } -export type ZodNonEmptyArray = ZodArray; +export type ZodNonEmptyArray = ZodArray; ///////////////////////////////////////// ///////////////////////////////////////// From 3ae4207f6ba239532f28863eb6bf715ec09e668f Mon Sep 17 00:00:00 2001 From: samchungy Date: Wed, 16 Aug 2023 00:34:13 +1000 Subject: [PATCH 2/5] Update readme --- README.md | 8 ++++++-- deno/lib/README.md | 8 ++++++-- deno/lib/types.ts | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d913ed9b4..ce96ceb8c 100644 --- a/README.md +++ b/README.md @@ -1425,12 +1425,16 @@ const nonEmptyStrings = z.string().array().nonempty({ ```ts z.string().array().min(5); // must contain 5 or more items +// the inferred type is now +// [string, string, string, string, string, ...string[]] + z.string().array().max(5); // must contain 5 or fewer items + z.string().array().length(5); // must contain 5 items exactly +// the inferred type is now +// [string, string, string, string, string] ``` -Unlike `.nonempty()` these methods do not change the inferred type. - ## Tuples Unlike arrays, tuples have a fixed number of elements and each element can have a different type. diff --git a/deno/lib/README.md b/deno/lib/README.md index d913ed9b4..ce96ceb8c 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -1425,12 +1425,16 @@ const nonEmptyStrings = z.string().array().nonempty({ ```ts z.string().array().min(5); // must contain 5 or more items +// the inferred type is now +// [string, string, string, string, string, ...string[]] + z.string().array().max(5); // must contain 5 or fewer items + z.string().array().length(5); // must contain 5 items exactly +// the inferred type is now +// [string, string, string, string, string] ``` -Unlike `.nonempty()` these methods do not change the inferred type. - ## Tuples Unlike arrays, tuples have a fixed number of elements and each element can have a different type. diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 0416cf0ff..12e31f698 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -1981,6 +1981,23 @@ type Tuple = R["length"] extends N : Tuple; type MinArray = [...Tuple, ...T[]]; +type MaxArray< + T, + N extends number, + R extends T[] = Tuple +> = R["length"] extends 0 + ? never + : R extends [infer U, ...infer V] + ? U extends undefined + ? never + : V extends T[] + ? R | MaxArray + : never + : never; + +type B = Tuple; + +type A = MaxArray; export type arrayOutputType< T extends ZodTypeAny, From 2cae2a51b885a21e91aefd6d528ae6d361a48a83 Mon Sep 17 00:00:00 2001 From: samchungy Date: Wed, 16 Aug 2023 00:38:53 +1000 Subject: [PATCH 3/5] remove generic from max --- deno/lib/types.ts | 19 +------------------ src/types.ts | 2 +- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 12e31f698..20ac8ed45 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -1981,23 +1981,6 @@ type Tuple = R["length"] extends N : Tuple; type MinArray = [...Tuple, ...T[]]; -type MaxArray< - T, - N extends number, - R extends T[] = Tuple -> = R["length"] extends 0 - ? never - : R extends [infer U, ...infer V] - ? U extends undefined - ? never - : V extends T[] - ? R | MaxArray - : never - : never; - -type B = Tuple; - -type A = MaxArray; export type arrayOutputType< T extends ZodTypeAny, @@ -2116,7 +2099,7 @@ export class ZodArray< }) as any; } - max(maxLength: N, message?: errorUtil.ErrMessage): this { + max(maxLength: number, message?: errorUtil.ErrMessage): this { return new ZodArray({ ...this._def, maxLength: { value: maxLength, message: errorUtil.toString(message) }, diff --git a/src/types.ts b/src/types.ts index 8af0827d3..d3bdee1ab 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2099,7 +2099,7 @@ export class ZodArray< }) as any; } - max(maxLength: N, message?: errorUtil.ErrMessage): this { + max(maxLength: number, message?: errorUtil.ErrMessage): this { return new ZodArray({ ...this._def, maxLength: { value: maxLength, message: errorUtil.toString(message) }, From 9539623d246c215114d6db2b867db040aa425bfe Mon Sep 17 00:00:00 2001 From: samchungy Date: Wed, 16 Aug 2023 10:23:14 +1000 Subject: [PATCH 4/5] update variable names --- deno/lib/types.ts | 10 +++++----- src/types.ts | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 20ac8ed45..a2eac08cb 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -1976,11 +1976,11 @@ export interface ZodArrayDef export type ArrayCardinality = "many" | "atleast" | "exactly"; -type Tuple = R["length"] extends N +type FixedArray = R["length"] extends N ? R - : Tuple; + : FixedArray; -type MinArray = [...Tuple, ...T[]]; +type MinArray = [...FixedArray, ...T[]]; export type arrayOutputType< T extends ZodTypeAny, @@ -1989,7 +1989,7 @@ export type arrayOutputType< > = Cardinality extends "atleast" ? MinArray : Cardinality extends "exactly" - ? Tuple + ? FixedArray : T["_output"][]; export class ZodArray< @@ -2002,7 +2002,7 @@ export class ZodArray< Cardinality extends "atleast" ? MinArray : Cardinality extends "exactly" - ? Tuple + ? FixedArray : T["_input"][] > { _parse(input: ParseInput): ParseReturnType { diff --git a/src/types.ts b/src/types.ts index d3bdee1ab..fa3340696 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1976,11 +1976,11 @@ export interface ZodArrayDef export type ArrayCardinality = "many" | "atleast" | "exactly"; -type Tuple = R["length"] extends N +type FixedArray = R["length"] extends N ? R - : Tuple; + : FixedArray; -type MinArray = [...Tuple, ...T[]]; +type MinArray = [...FixedArray, ...T[]]; export type arrayOutputType< T extends ZodTypeAny, @@ -1989,7 +1989,7 @@ export type arrayOutputType< > = Cardinality extends "atleast" ? MinArray : Cardinality extends "exactly" - ? Tuple + ? FixedArray : T["_output"][]; export class ZodArray< @@ -2002,7 +2002,7 @@ export class ZodArray< Cardinality extends "atleast" ? MinArray : Cardinality extends "exactly" - ? Tuple + ? FixedArray : T["_input"][] > { _parse(input: ParseInput): ParseReturnType { From 68771b908207b8d6be0c068755ae10f4fe0c4579 Mon Sep 17 00:00:00 2001 From: samchungy Date: Wed, 16 Aug 2023 10:28:31 +1000 Subject: [PATCH 5/5] add .length type test --- deno/lib/__tests__/array.test.ts | 3 +++ src/__tests__/array.test.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/deno/lib/__tests__/array.test.ts b/deno/lib/__tests__/array.test.ts index e595bfb50..b20571174 100644 --- a/deno/lib/__tests__/array.test.ts +++ b/deno/lib/__tests__/array.test.ts @@ -17,6 +17,9 @@ util.assertEqual<[string, ...string[]], t1>(true); type t2 = z.infer; util.assertEqual<[string, string, ...string[]], t2>(true); +type t3 = z.infer; +util.assertEqual<[string, string], t3>(true); + test("passing validations", () => { minTwo.parse(["a", "a"]); minTwo.parse(["a", "a", "a"]); diff --git a/src/__tests__/array.test.ts b/src/__tests__/array.test.ts index 94ee5ac01..cb141a80c 100644 --- a/src/__tests__/array.test.ts +++ b/src/__tests__/array.test.ts @@ -16,6 +16,9 @@ util.assertEqual<[string, ...string[]], t1>(true); type t2 = z.infer; util.assertEqual<[string, string, ...string[]], t2>(true); +type t3 = z.infer; +util.assertEqual<[string, string], t3>(true); + test("passing validations", () => { minTwo.parse(["a", "a"]); minTwo.parse(["a", "a", "a"]);