zodselect 1.2.9 โ†’ 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -139,6 +139,14 @@ const schema = refineSchema(UserSchema, {
139
139
  }
140
140
  ```
141
141
 
142
+ A field the schema doesn't have is a type error, at any depth and even beside valid fields:
143
+
144
+ ```ts
145
+ refineSchema(UserSchema, { firstName: true, lastNmae: true }); // โœ– 'lastNmae' is not a field of UserSchema
146
+ ```
147
+
148
+ Code that builds a selection generically, whose type the check can't evaluate, calls `refineSchemaUnchecked` instead: the same refinement, with a field the schema doesn't have skipped.
149
+
142
150
  ---
143
151
 
144
152
  ## ๐Ÿงช Refine Field Types Inline
@@ -2,6 +2,18 @@ import { core, z, ZodAny, ZodArray, ZodBoolean, ZodDate, ZodLiteral, ZodNever, Z
2
2
  import { IsAny, IsJsonType } from './types.js';
3
3
  type ApplyOptionalNullable<T, U extends ZodType> = IsAny<T, U, unknown extends T ? U : undefined extends T ? null extends T ? ZodOptional<ZodNullable<U>> : ZodOptional<U> : null extends T ? ZodNullable<U> : U>;
4
4
  type DepthLimit = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
5
+ /** `TShape` with every key `T` doesn't have, at any depth, as `never`, so a misspelt select is a type error even beside valid keys. */
6
+ type Exact<TShape, T> = {
7
+ [K in keyof TShape]: K extends FieldKeys<T> ? TShape[K] extends ((schema: never) => unknown) | boolean | ZodType ? TShape[K] : TShape[K] extends object ? Exact<TShape[K], FieldObjects<FieldAt<T, K>>> : TShape[K] : never;
8
+ };
9
+ /** What the field `TKey` holds in any object of `T`. */
10
+ type FieldAt<T, TKey> = T extends unknown ? TKey extends keyof T ? T[TKey] : never : never;
11
+ /** The declared keys of every object in `T`, each of a union's own. */
12
+ type FieldKeys<T> = T extends unknown ? Extract<keyof {
13
+ [K in keyof T as string extends K ? never : number extends K ? never : K]: unknown;
14
+ }, string> : never;
15
+ /** The objects a field of type `T` holds, through arrays: what a nested select picks within. */
16
+ type FieldObjects<T> = T extends readonly (infer E)[] ? FieldObjects<E> : T extends Date ? never : T extends object ? T : never;
5
17
  type InternalZodify<T, TDepth extends number = 0> = TDepth extends 9 ? ZodType : IsAny<T, ZodAny, T extends string ? string extends T ? ZodString : ZodLiteral<T> : T extends number ? number extends T ? ZodNumber : ZodLiteral<T> : T extends boolean ? boolean extends T ? ZodBoolean : ZodLiteral<T> : T extends Date ? ZodDate : unknown extends T ? ZodUnknown : T extends Array<infer U> ? ZodArray<Zodify<U, NextDepth<TDepth>>> : T extends object ? IsJsonType<T, true, ZodObject<{
6
18
  [K in keyof T]-?: Zodify<T[K], NextDepth<TDepth>>;
7
19
  }, core.$strict>, ZodType<T>> : never>;
@@ -13,7 +25,7 @@ type ReapplyOptionalNullable<T, U extends z.ZodType> = T extends ZodOptional<Zod
13
25
  export type RefinedSchema<T extends ZodType<object> | ZodUnion, TShape extends RefineSchema<T, TIsSimple>, TIsSimple extends boolean> = T extends ZodUnion ? RefinedUnionSchema<T, TShape> : T extends ZodType<object> ? RefinedTypeSchema<z.infer<T>, TShape> : never;
14
26
  export type RefinedTypeSchema<T extends object, TShape, TDepth extends number = 0> = TDepth extends keyof DepthLimit ? ZodObject<{
15
27
  [K in keyof T & keyof TShape]: TShape[K] extends (schema: infer _S) => ZodType ? ReturnType<TShape[K]> : TShape[K] extends ZodType ? TShape[K] : TShape[K] extends boolean ? ZodifyField<T, K> : TShape[K] extends object ? Exclude<T[K], null | undefined> extends Array<infer U> ? [Extract<U, object>] extends [never] ? Zodify<T[K]> : ApplyOptionalNullable<T[K], z.ZodArray<RefinedVariants<Extract<U, object>, TShape[K], NextDepth<TDepth>>>> : [Extract<Exclude<T[K], null | undefined>, object>] extends [never] ? ZodNever : ApplyOptionalNullable<T[K], RefinedVariants<Extract<Exclude<T[K], null | undefined>, object>, TShape[K], NextDepth<TDepth>>> : ZodNever;
16
- }, core.$strict> : any;
28
+ }, core.$strip> : any;
17
29
  export type RefinedUnionSchema<T extends ZodUnion, TShape> = ZodUnion<T['options'] extends Readonly<[infer A, ...infer Rest]> ? Rest extends ZodType[] ? [
18
30
  ReapplyOptionalNullable<A, A extends ZodType<object> ? RefinedTypeSchema<z.infer<A>, TShape> : Extract<A, ZodType>>,
19
31
  ...{
@@ -43,5 +55,11 @@ type ZodifyField<T, TKey extends keyof T> = unknown extends T[TKey] ? Partial<Pi
43
55
  type ZodifyLiteral<T, TElse> = [
44
56
  T
45
57
  ] extends [boolean | number | string] ? [T] extends [boolean] ? boolean extends T ? ZodBoolean : ZodLiteral<T> : string extends T ? [T] extends [string] ? ZodString : TElse : number extends T ? [T] extends [number] ? ZodNumber : TElse : ZodLiteral<T> : TElse;
46
- export declare function refineSchema<T extends ZodType<object> | ZodUnion, TShape extends RefineSchema<T, false>>(schema: T, shape: TShape): RefinedSchema<T, TShape, false>;
58
+ /** `shape`'s fields of `schema`. A key the schema doesn't have, at any depth, is a type error. */
59
+ export declare function refineSchema<T extends ZodType<object> | ZodUnion, TShape extends RefineSchema<T, false>>(schema: T, shape: TShape & Exact<TShape, z.infer<T>>): RefinedSchema<T, TShape, false>;
60
+ /**
61
+ * {@link refineSchema} for a shape whose type is still generic, which the exact key check can't evaluate.
62
+ * Prefer {@link refineSchema}: a key the schema doesn't have is skipped here, not refused.
63
+ */
64
+ export declare function refineSchemaUnchecked<T extends ZodType<object> | ZodUnion, TShape extends RefineSchema<T, false>>(schema: T, shape: TShape): RefinedSchema<T, TShape, false>;
47
65
  export {};
@@ -1,22 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  import { isZodArray, isZodCatch, isZodDefault, isZodLazy, isZodNullable, isZodObject, isZodOptional, isZodType, isZodUnion } from './utilities.js';
3
- // Main function to refine the schema
3
+ /** `shape`'s fields of `schema`. A key the schema doesn't have, at any depth, is a type error. */
4
4
  export function refineSchema(schema, shape) {
5
- if (isZodObject(schema)) {
6
- const refinedShape = {};
7
- const schemaShape = schema.shape;
8
- for (const key in shape) {
9
- if (key in schemaShape && shape[key] !== false) {
10
- refinedShape[key] = refineSchemaField(schemaShape[key], shape[key]);
11
- }
12
- }
13
- return z.object(refinedShape);
14
- }
15
- else if (isZodUnion(schema)) {
16
- const refinedOptions = schema.options.map(option => refineSchemaField(option, shape));
17
- return z.union(refinedOptions);
18
- }
19
- throw new Error('Unsupported schema type for refinement');
5
+ return refineSchemaUnchecked(schema, shape);
20
6
  }
21
7
  // Helper function to refine a single schema field
22
8
  function refineSchemaField(fieldSchema, fieldShape) {
@@ -30,10 +16,10 @@ function refineSchemaField(fieldSchema, fieldShape) {
30
16
  return fieldShape; // Use redefined type
31
17
  }
32
18
  else if (isZodObject(fieldSchema)) {
33
- return refineSchema(fieldSchema, fieldShape); // Recursively refine nested objects
19
+ return refineSchemaUnchecked(fieldSchema, fieldShape); // Recursively refine nested objects
34
20
  }
35
21
  else if (isZodUnion(fieldSchema)) {
36
- return refineSchema(fieldSchema, fieldShape);
22
+ return refineSchemaUnchecked(fieldSchema, fieldShape);
37
23
  }
38
24
  else if (isZodArray(fieldSchema)) {
39
25
  // Recursively refine array items
@@ -54,3 +40,24 @@ function refineSchemaField(fieldSchema, fieldShape) {
54
40
  }
55
41
  return fieldSchema;
56
42
  }
43
+ /**
44
+ * {@link refineSchema} for a shape whose type is still generic, which the exact key check can't evaluate.
45
+ * Prefer {@link refineSchema}: a key the schema doesn't have is skipped here, not refused.
46
+ */
47
+ export function refineSchemaUnchecked(schema, shape) {
48
+ if (isZodObject(schema)) {
49
+ const refinedShape = {};
50
+ const schemaShape = schema.shape;
51
+ for (const key in shape) {
52
+ if (key in schemaShape && shape[key] !== false) {
53
+ refinedShape[key] = refineSchemaField(schemaShape[key], shape[key]);
54
+ }
55
+ }
56
+ return z.object(refinedShape);
57
+ }
58
+ else if (isZodUnion(schema)) {
59
+ const refinedOptions = schema.options.map(option => refineSchemaField(option, shape));
60
+ return z.union(refinedOptions);
61
+ }
62
+ throw new Error('Unsupported schema type for refinement');
63
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zodselect",
3
- "version": "1.2.9",
3
+ "version": "1.3.0",
4
4
  "description": "Type-safe selection utility built on top of Zod. Allows for strongly typed field selection, schema merging, and runtime refinement for frontend or backend use.",
5
5
  "author": "SecureDataSystems",
6
6
  "license": "MIT",