From 1d0258d21815af38a94ccb181cd85fb52af9e160 Mon Sep 17 00:00:00 2001 From: bsickler Date: Thu, 24 Oct 2024 15:47:00 -0700 Subject: [PATCH] respects optionality of object keys without considering all undefined values as optional attributes --- deno/lib/README.md | 4 ++++ deno/lib/__tests__/object.test.ts | 4 ++-- deno/lib/helpers/util.ts | 30 ++++++++++++++++++++++-------- deno/lib/types.ts | 14 ++------------ src/__tests__/object.test.ts | 4 ++-- src/helpers/util.ts | 30 ++++++++++++++++++++++-------- src/types.ts | 14 ++------------ 7 files changed, 56 insertions(+), 44 deletions(-) diff --git a/deno/lib/README.md b/deno/lib/README.md index a721693b1..cdae9403c 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -491,6 +491,7 @@ There are a growing number of tools that are built atop or support Zod natively! - [`sveltekit-superforms`](https://github.com/ciscoheat/sveltekit-superforms): Supercharged form library for SvelteKit with Zod validation. - [`mobx-zod-form`](https://github.com/MonoidDev/mobx-zod-form): Data-first form builder based on MobX & Zod. - [`@vee-validate/zod`](https://github.com/logaretm/vee-validate/tree/main/packages/zod): Form library for Vue.js with Zod schema validation. +- [`zod-form-renderer`](https://github.com/thepeaklab/zod-form-renderer): Auto-infer form fields from zod schema and render them with react-hook-form with E2E type safety. #### Zod to X @@ -505,6 +506,7 @@ There are a growing number of tools that are built atop or support Zod natively! - [`zod-openapi`](https://github.com/samchungy/zod-openapi): Create full OpenAPI v3.x documentation from Zod schemas. - [`fastify-zod-openapi`](https://github.com/samchungy/fastify-zod-openapi): Fastify type provider, validation, serialization and @fastify/swagger support for Zod schemas. - [`typeschema`](https://typeschema.com/): Universal adapter for schema validation. +- [`zodex`](https://github.com/commonbaseapp/zodex): (De)serialization for zod schemas #### X to Zod @@ -538,11 +540,13 @@ There are a growing number of tools that are built atop or support Zod natively! - [`freerstore`](https://github.com/JacobWeisenburger/freerstore): Firestore cost optimizer. - [`slonik`](https://github.com/gajus/slonik/tree/gajus/add-zod-validation-backwards-compatible#runtime-validation-and-static-type-inference): Node.js Postgres client with strong Zod integration. +- [`schemql`](https://github.com/a2lix/schemql): Enhances your SQL workflow by combining raw SQL with targeted type safety and schema validation. - [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod. - [`pastel`](https://github.com/vadimdemedes/pastel): Create CLI applications with react, zod, and ink. - [`zod-xlsx`](https://github.com/sidwebworks/zod-xlsx): A xlsx based resource validator using Zod schemas. - [`znv`](https://github.com/lostfictions/znv): Type-safe environment parsing and validation for Node.js with Zod schemas. - [`zod-config`](https://github.com/alexmarqs/zod-config): Load configurations across multiple sources with flexible adapters, ensuring type safety with Zod. +- [`unplugin-environment`](https://github.com/r17x/js/tree/main/packages/unplugin-environment#readme): A plugin for loading enviroment variables safely with schema validation, simple with virtual module, type-safe with intellisense, and better DX 🔥 🚀 👷. Powered by Zod. #### Utilities for Zod diff --git a/deno/lib/__tests__/object.test.ts b/deno/lib/__tests__/object.test.ts index ff636a078..4b11cda75 100644 --- a/deno/lib/__tests__/object.test.ts +++ b/deno/lib/__tests__/object.test.ts @@ -290,9 +290,9 @@ test("inferred type for unknown/any keys", () => { myType, { anyOptional?: any; - anyRequired?: any; + anyRequired: any; unknownOptional?: unknown; - unknownRequired?: unknown; + unknownRequired: unknown; } >(true); }); diff --git a/deno/lib/helpers/util.ts b/deno/lib/helpers/util.ts index 74ecd7863..b52d03c86 100644 --- a/deno/lib/helpers/util.ts +++ b/deno/lib/helpers/util.ts @@ -1,3 +1,5 @@ +import type { ZodDefault, ZodOptional, ZodRawShape, ZodTypeAny } from "../types.ts"; + export namespace util { type AssertEqual = (() => V extends T ? 1 : 2) extends < V @@ -101,17 +103,29 @@ export namespace objectUtil { [k in Exclude]: U[k]; } & V; - type optionalKeys = { - [k in keyof T]: {} extends Pick ? k : never; + type ObjectField = '_output' | '_input'; + + type optionalKeys = { + [k in keyof T]: T[k] extends ZodOptional + ? k + : T[k] extends ZodDefault + ? I extends '_output' ? never : k + : never; }[keyof T]; - type requiredKeys = { - [k in keyof T]: {} extends Pick ? never : k; + + type requiredKeys = { + [k in keyof T]: T[k] extends ZodOptional + ? never + : T[k] extends ZodDefault + ? I extends '_output' ? k : never + : k; }[keyof T]; - export type addQuestionMarks = { - [K in requiredKeys]: T[K]; + + export type addQuestionMarks = { + [K in requiredKeys]: Shape[K][I]; } & { - [K in optionalKeys]?: T[K]; - } & { [k in keyof T]?: unknown }; + [K in optionalKeys]?: Shape[K][I] | undefined; + } & { [k in keyof Shape]?: unknown }; export type identity = T; export type flatten = identity<{ [k in keyof T]: T[k] }>; diff --git a/deno/lib/types.ts b/deno/lib/types.ts index bb2f08519..b97e155b4 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -2330,27 +2330,17 @@ export type objectOutputType< Shape extends ZodRawShape, Catchall extends ZodTypeAny, UnknownKeys extends UnknownKeysParam = UnknownKeysParam -> = objectUtil.flatten< - objectUtil.addQuestionMarks> -> & +> = objectUtil.flatten> & CatchallOutput & PassthroughType; -export type baseObjectOutputType = { - [k in keyof Shape]: Shape[k]["_output"]; -}; - export type objectInputType< Shape extends ZodRawShape, Catchall extends ZodTypeAny, UnknownKeys extends UnknownKeysParam = UnknownKeysParam -> = objectUtil.flatten> & +> = objectUtil.flatten> & CatchallInput & PassthroughType; -export type baseObjectInputType = - objectUtil.addQuestionMarks<{ - [k in keyof Shape]: Shape[k]["_input"]; - }>; export type CatchallOutput = ZodType extends T ? unknown diff --git a/src/__tests__/object.test.ts b/src/__tests__/object.test.ts index 879351f83..ff6b153ff 100644 --- a/src/__tests__/object.test.ts +++ b/src/__tests__/object.test.ts @@ -289,9 +289,9 @@ test("inferred type for unknown/any keys", () => { myType, { anyOptional?: any; - anyRequired?: any; + anyRequired: any; unknownOptional?: unknown; - unknownRequired?: unknown; + unknownRequired: unknown; } >(true); }); diff --git a/src/helpers/util.ts b/src/helpers/util.ts index 74ecd7863..6440f7484 100644 --- a/src/helpers/util.ts +++ b/src/helpers/util.ts @@ -1,3 +1,5 @@ +import type { ZodDefault, ZodOptional, ZodRawShape, ZodTypeAny } from "../types"; + export namespace util { type AssertEqual = (() => V extends T ? 1 : 2) extends < V @@ -101,17 +103,29 @@ export namespace objectUtil { [k in Exclude]: U[k]; } & V; - type optionalKeys = { - [k in keyof T]: {} extends Pick ? k : never; + type ObjectField = '_output' | '_input'; + + type optionalKeys = { + [k in keyof T]: T[k] extends ZodOptional + ? k + : T[k] extends ZodDefault + ? I extends '_output' ? never : k + : never; }[keyof T]; - type requiredKeys = { - [k in keyof T]: {} extends Pick ? never : k; + + type requiredKeys = { + [k in keyof T]: T[k] extends ZodOptional + ? never + : T[k] extends ZodDefault + ? I extends '_output' ? k : never + : k; }[keyof T]; - export type addQuestionMarks = { - [K in requiredKeys]: T[K]; + + export type addQuestionMarks = { + [K in requiredKeys]: Shape[K][I]; } & { - [K in optionalKeys]?: T[K]; - } & { [k in keyof T]?: unknown }; + [K in optionalKeys]?: Shape[K][I] | undefined; + } & { [k in keyof Shape]?: unknown }; export type identity = T; export type flatten = identity<{ [k in keyof T]: T[k] }>; diff --git a/src/types.ts b/src/types.ts index 5aa30b900..e516dfd4d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2330,27 +2330,17 @@ export type objectOutputType< Shape extends ZodRawShape, Catchall extends ZodTypeAny, UnknownKeys extends UnknownKeysParam = UnknownKeysParam -> = objectUtil.flatten< - objectUtil.addQuestionMarks> -> & +> = objectUtil.flatten> & CatchallOutput & PassthroughType; -export type baseObjectOutputType = { - [k in keyof Shape]: Shape[k]["_output"]; -}; - export type objectInputType< Shape extends ZodRawShape, Catchall extends ZodTypeAny, UnknownKeys extends UnknownKeysParam = UnknownKeysParam -> = objectUtil.flatten> & +> = objectUtil.flatten> & CatchallInput & PassthroughType; -export type baseObjectInputType = - objectUtil.addQuestionMarks<{ - [k in keyof Shape]: Shape[k]["_input"]; - }>; export type CatchallOutput = ZodType extends T ? unknown