Skip to content

Commit

Permalink
Remove deepPartial
Browse files Browse the repository at this point in the history
  • Loading branch information
colinhacks committed Jul 19, 2024
1 parent 0dedd82 commit 349932d
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 174 deletions.
66 changes: 33 additions & 33 deletions packages/zod/src/helpers/partialUtil.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type {
ZodArray,
ZodNullable,
ZodObject,
ZodOptional,
ZodRawShape,
ZodTuple,
ZodTupleItems,
ZodTypeAny,
} from "../index.js";
// import type {
// ZodArray,
// ZodNullable,
// ZodObject,
// ZodOptional,
// ZodRawShape,
// ZodTuple,
// ZodTupleItems,
// ZodTypeAny,
// } from "../index.js";

// export type DeepPartial<T extends AnyZodObject> = T extends AnyZodObject
// ? ZodObject<
Expand All @@ -34,29 +34,29 @@ import type {
// ? "object" // T extends ZodOptional<any> // ? 'optional' // :
// : "rest"];

export type DeepPartial<T extends ZodTypeAny> = T extends ZodObject<ZodRawShape>
? ZodObject<
{ [k in keyof T["shape"]]: ZodOptional<DeepPartial<T["shape"][k]>> },
T["_def"]["unknownKeys"],
T["_def"]["catchall"]
>
: T extends ZodArray<infer Type, infer Card>
? ZodArray<DeepPartial<Type>, Card>
: T extends ZodOptional<infer Type>
? ZodOptional<DeepPartial<Type>>
: T extends ZodNullable<infer Type>
? ZodNullable<DeepPartial<Type>>
: T extends ZodTuple<infer Items>
? {
[k in keyof Items]: Items[k] extends ZodTypeAny
? DeepPartial<Items[k]>
: never;
} extends infer PI
? PI extends ZodTupleItems
? ZodTuple<PI>
: never
: never
: T;
// export type DeepPartial<T extends ZodTypeAny> = T extends ZodObject<ZodRawShape>
// ? ZodObject<
// { [k in keyof T["shape"]]: ZodOptional<DeepPartial<T["shape"][k]>> },
// T["_def"]["unknownKeys"],
// T["_def"]["catchall"]
// >
// : T extends ZodArray<infer Type, infer Card>
// ? ZodArray<DeepPartial<Type>, Card>
// : T extends ZodOptional<infer Type>
// ? ZodOptional<DeepPartial<Type>>
// : T extends ZodNullable<infer Type>
// ? ZodNullable<DeepPartial<Type>>
// : T extends ZodTuple<infer Items>
// ? {
// [k in keyof Items]: Items[k] extends ZodTypeAny
// ? DeepPartial<Items[k]>
// : never;
// } extends infer PI
// ? PI extends ZodTupleItems
// ? ZodTuple<PI>
// : never
// : never
// : T;
// {
// // optional: T extends ZodOptional<ZodTypeAny> ? T : ZodOptional<T>;
// // array: T extends ZodArray<infer Type> ? ZodArray<DeepPartial<Type>> : never;
Expand Down
71 changes: 35 additions & 36 deletions packages/zod/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
type enumUtil,
errorUtil,
type objectUtil,
type partialUtil,
} from "./helpers/index.js";

import {
Expand Down Expand Up @@ -2702,38 +2701,38 @@ export type noUnrecognized<Obj extends object, Shape extends object> = {
[k in keyof Obj]: k extends keyof Shape ? Obj[k] : never;
};

function deepPartialify(schema: ZodTypeAny): any {
if (schema instanceof ZodObject) {
const newShape: any = {};

for (const key in schema.shape) {
const fieldSchema = schema.shape[key];
newShape[key] = ZodOptional.create(deepPartialify(fieldSchema));
}
return new ZodObject({
...schema._def,
shape: () => newShape,
}) as any;
}
if (schema instanceof ZodArray) {
return new ZodArray({
...schema._def,
type: deepPartialify(schema.element),
});
}
if (schema instanceof ZodOptional) {
return ZodOptional.create(deepPartialify(schema.unwrap()));
}
if (schema instanceof ZodNullable) {
return ZodNullable.create(deepPartialify(schema.unwrap()));
}
if (schema instanceof ZodTuple) {
return ZodTuple.create(
schema.items.map((item: any) => deepPartialify(item))
);
}
return schema;
}
// function deepPartialify(schema: ZodTypeAny): any {
// if (schema instanceof ZodObject) {
// const newShape: any = {};

// for (const key in schema.shape) {
// const fieldSchema = schema.shape[key];
// newShape[key] = ZodOptional.create(deepPartialify(fieldSchema));
// }
// return new ZodObject({
// ...schema._def,
// shape: () => newShape,
// }) as any;
// }
// if (schema instanceof ZodArray) {
// return new ZodArray({
// ...schema._def,
// type: deepPartialify(schema.element),
// });
// }
// if (schema instanceof ZodOptional) {
// return ZodOptional.create(deepPartialify(schema.unwrap()));
// }
// if (schema instanceof ZodNullable) {
// return ZodNullable.create(deepPartialify(schema.unwrap()));
// }
// if (schema instanceof ZodTuple) {
// return ZodTuple.create(
// schema.items.map((item: any) => deepPartialify(item))
// );
// }
// return schema;
// }

export class ZodObject<
T extends ZodRawShape,
Expand Down Expand Up @@ -3151,9 +3150,9 @@ export class ZodObject<
/**
* @deprecated
*/
deepPartial(): partialUtil.DeepPartial<this> {
return deepPartialify(this) as any;
}
// deepPartial(): partialUtil.DeepPartial<this> {
// return deepPartialify(this) as any;
// }

partial(): ZodObject<
{ [k in keyof T]: ZodOptional<T[k]> },
Expand Down
209 changes: 104 additions & 105 deletions packages/zod/tests/partials.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { expect, test } from "vitest";

import { util } from "../src/helpers/index.js";
import * as z from "../src/index.js";
import { ZodNullable, ZodOptional } from "../src/index.js";

const nested = z.object({
name: z.string(),
Expand Down Expand Up @@ -35,100 +34,110 @@ test("shallow partial parse", () => {
});
});

test("deep partial inference", () => {
const deep = nested.deepPartial();
const asdf = deep.shape.array.unwrap().element.shape.asdf.unwrap();
asdf.parse("asdf");
type deep = z.infer<typeof deep>;
type correct = {
array?: { asdf?: string }[];
name?: string | undefined;
age?: number | undefined;
outer?: { inner?: string | undefined } | undefined;
};

util.assertEqual<deep, correct>(true);
});

test("deep partial parse", () => {
const deep = nested.deepPartial();

expect(deep.shape.name instanceof z.ZodOptional).toBe(true);
expect(deep.shape.outer instanceof z.ZodOptional).toBe(true);
expect(deep.shape.outer._def.innerType instanceof z.ZodObject).toBe(true);
expect(
deep.shape.outer._def.innerType.shape.inner instanceof z.ZodOptional
).toBe(true);
expect(
deep.shape.outer._def.innerType.shape.inner._def.innerType instanceof
z.ZodString
).toBe(true);
});

test("deep partial runtime tests", () => {
const deep = nested.deepPartial();
deep.parse({});
deep.parse({
outer: {},
});
deep.parse({
name: "asdf",
age: 23143,
outer: {
inner: "adsf",
},
});
});

test("deep partial optional/nullable", () => {
const schema = z
.object({
name: z.string().optional(),
age: z.number().nullable(),
})
.deepPartial();

expect(schema.shape.name.unwrap()).toBeInstanceOf(ZodOptional);
expect(schema.shape.age.unwrap()).toBeInstanceOf(ZodNullable);
});

test("deep partial tuple", () => {
const schema = z
.object({
tuple: z.tuple([
z.object({
name: z.string().optional(),
age: z.number().nullable(),
}),
]),
})
.deepPartial();

expect(schema.shape.tuple.unwrap().items[0].shape.name).toBeInstanceOf(
ZodOptional
);
});

test("deep partial inference", () => {
const mySchema = z.object({
name: z.string(),
array: z.array(z.object({ asdf: z.string() })),
tuple: z.tuple([z.object({ value: z.string() })]),
});

const partialed = mySchema.deepPartial();
type partialed = z.infer<typeof partialed>;
type expected = {
name?: string | undefined;
array?:
| {
asdf?: string | undefined;
}[]
| undefined;
tuple?: [{ value?: string }] | undefined;
};
util.assertEqual<expected, partialed>(true);
});
// test("deep partial inference", () => {
// const deep = nested.deepPartial();
// const asdf = deep.shape.array.unwrap().element.shape.asdf.unwrap();
// asdf.parse("asdf");
// type deep = z.infer<typeof deep>;
// type correct = {
// array?: { asdf?: string }[];
// name?: string | undefined;
// age?: number | undefined;
// outer?: { inner?: string | undefined } | undefined;
// };

// util.assertEqual<deep, correct>(true);
// });

// test("deep partial parse", () => {
// const deep = nested.deepPartial();

// expect(deep.shape.name instanceof z.ZodOptional).toBe(true);
// expect(deep.shape.outer instanceof z.ZodOptional).toBe(true);
// expect(deep.shape.outer._def.innerType instanceof z.ZodObject).toBe(true);
// expect(
// deep.shape.outer._def.innerType.shape.inner instanceof z.ZodOptional
// ).toBe(true);
// expect(
// deep.shape.outer._def.innerType.shape.inner._def.innerType instanceof
// z.ZodString
// ).toBe(true);
// });

// test("deep partial runtime tests", () => {
// const deep = nested.deepPartial();
// deep.parse({});
// deep.parse({
// outer: {},
// });
// deep.parse({
// name: "asdf",
// age: 23143,
// outer: {
// inner: "adsf",
// },
// });
// });

// test("deep partial optional/nullable", () => {
// const schema = z
// .object({
// name: z.string().optional(),
// age: z.number().nullable(),
// })
// .deepPartial();

// expect(schema.shape.name.unwrap()).toBeInstanceOf(ZodOptional);
// expect(schema.shape.age.unwrap()).toBeInstanceOf(ZodNullable);
// });

// test("deep partial tuple", () => {
// const schema = z
// .object({
// tuple: z.tuple([
// z.object({
// name: z.string().optional(),
// age: z.number().nullable(),
// }),
// ]),
// })
// .deepPartial();

// expect(schema.shape.tuple.unwrap().items[0].shape.name).toBeInstanceOf(
// ZodOptional
// );
// });

// test("deep partial inference", () => {
// const mySchema = z.object({
// name: z.string(),
// array: z.array(z.object({ asdf: z.string() })),
// tuple: z.tuple([z.object({ value: z.string() })]),
// });

// const partialed = mySchema.deepPartial();
// type partialed = z.infer<typeof partialed>;
// type expected = {
// name?: string | undefined;
// array?:
// | {
// asdf?: string | undefined;
// }[]
// | undefined;
// tuple?: [{ value?: string }] | undefined;
// };
// util.assertEqual<expected, partialed>(true);
// });

// test("deeppartial array", () => {
// const schema = z.object({ array: z.string().array().min(42) }).deepPartial();

// // works as expected
// schema.parse({});

// // should be false, but is true
// expect(schema.safeParse({ array: [] }).success).toBe(false);
// });

test("required", () => {
const object = z.object({
Expand Down Expand Up @@ -240,13 +249,3 @@ test("partial with mask -- ignore falsy values", async () => {
masked.parse({ country: "US" });
await masked.parseAsync({ country: "US" });
});

test("deeppartial array", () => {
const schema = z.object({ array: z.string().array().min(42) }).deepPartial();

// works as expected
schema.parse({});

// should be false, but is true
expect(schema.safeParse({ array: [] }).success).toBe(false);
});

0 comments on commit 349932d

Please sign in to comment.