Skip to content

Commit

Permalink
Add mask parameter to .required method (#1315)
Browse files Browse the repository at this point in the history
  • Loading branch information
SrBrahma committed Oct 5, 2022
1 parent 95a0315 commit 4709160
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 18 deletions.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,42 @@ const deepPartialUser = user.deepPartial();

> Important limitation: deep partials only work as expected in hierarchies of objects, arrays, and tuples.

### `.required`

Contrary to the `.partial` method, the `.required` method makes all properties required.

Starting from this object:

```ts
const user = z.object({
email: z.string()
username: z.string(),
}).partial();
// { email?: string | undefined; username?: string | undefined }
```

We can create a required version:

```ts
const requiredUser = user.required();
// { email: string; username: string }
```

You can also specify which properties to make required:

```ts
const requiredEmail = user.required({
email: true,
});
/*
{
email: string;
username?: string | undefined;
}
*/
```

### `.passthrough`

By default Zod object schemas strip out unrecognized keys during parsing.
Expand Down
36 changes: 36 additions & 0 deletions deno/lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,42 @@ const deepPartialUser = user.deepPartial();

> Important limitation: deep partials only work as expected in hierarchies of objects, arrays, and tuples.

### `.required`

Contrary to the `.partial` method, the `.required` method makes all properties required.

Starting from this object:

```ts
const user = z.object({
email: z.string()
username: z.string(),
}).partial();
// { email?: string | undefined; username?: string | undefined }
```

We can create a required version:

```ts
const requiredUser = user.required();
// { email: string; username: string }
```

You can also specify which properties to make required:

```ts
const requiredEmail = user.required({
email: true,
});
/*
{
email: string;
username?: string | undefined;
}
*/
```

### `.passthrough`

By default Zod object schemas strip out unrecognized keys during parsing.
Expand Down
17 changes: 16 additions & 1 deletion deno/lib/__tests__/partials.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,22 @@ test("required", () => {
expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault);
});

test("with mask", async () => {
test("required with mask", () => {
const object = z.object({
name: z.string(),
age: z.number().optional(),
field: z.string().optional().default("asdf"),
country: z.string().optional(),
});

const requiredObject = object.required({ age: true });
expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString);
expect(requiredObject.shape.age).toBeInstanceOf(z.ZodNumber);
expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault);
expect(requiredObject.shape.country).toBeInstanceOf(z.ZodOptional);
});

test("partial with mask", async () => {
const object = z.object({
name: z.string(),
age: z.number().optional(),
Expand Down
41 changes: 33 additions & 8 deletions deno/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1931,16 +1931,41 @@ export class ZodObject<
{ [k in keyof T]: deoptional<T[k]> },
UnknownKeys,
Catchall
> {
>;
required<Mask extends { [k in keyof T]?: true }>(
mask: Mask
): ZodObject<
objectUtil.noNever<{
[k in keyof T]: k extends keyof Mask ? deoptional<T[k]> : T[k];
}>,
UnknownKeys,
Catchall
>;
required(mask?: any) {
const newShape: any = {};
for (const key in this.shape) {
const fieldSchema = this.shape[key];
let newField = fieldSchema;
while (newField instanceof ZodOptional) {
newField = (newField as ZodOptional<any>)._def.innerType;
}
if (mask) {
util.objectKeys(this.shape).map((key) => {
if (util.objectKeys(mask).indexOf(key) === -1) {
newShape[key] = this.shape[key];
} else {
const fieldSchema = this.shape[key];
let newField = fieldSchema;
while (newField instanceof ZodOptional) {
newField = (newField as ZodOptional<any>)._def.innerType;
}
newShape[key] = newField;
}
});
} else {
for (const key in this.shape) {
const fieldSchema = this.shape[key];
let newField = fieldSchema;
while (newField instanceof ZodOptional) {
newField = (newField as ZodOptional<any>)._def.innerType;
}

newShape[key] = newField;
newShape[key] = newField;
}
}
return new ZodObject({
...this._def,
Expand Down
17 changes: 16 additions & 1 deletion src/__tests__/partials.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,22 @@ test("required", () => {
expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault);
});

test("with mask", async () => {
test("required with mask", () => {
const object = z.object({
name: z.string(),
age: z.number().optional(),
field: z.string().optional().default("asdf"),
country: z.string().optional(),
});

const requiredObject = object.required({ age: true });
expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString);
expect(requiredObject.shape.age).toBeInstanceOf(z.ZodNumber);
expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault);
expect(requiredObject.shape.country).toBeInstanceOf(z.ZodOptional);
});

test("partial with mask", async () => {
const object = z.object({
name: z.string(),
age: z.number().optional(),
Expand Down
41 changes: 33 additions & 8 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1931,16 +1931,41 @@ export class ZodObject<
{ [k in keyof T]: deoptional<T[k]> },
UnknownKeys,
Catchall
> {
>;
required<Mask extends { [k in keyof T]?: true }>(
mask: Mask
): ZodObject<
objectUtil.noNever<{
[k in keyof T]: k extends keyof Mask ? deoptional<T[k]> : T[k];
}>,
UnknownKeys,
Catchall
>;
required(mask?: any) {
const newShape: any = {};
for (const key in this.shape) {
const fieldSchema = this.shape[key];
let newField = fieldSchema;
while (newField instanceof ZodOptional) {
newField = (newField as ZodOptional<any>)._def.innerType;
}
if (mask) {
util.objectKeys(this.shape).map((key) => {
if (util.objectKeys(mask).indexOf(key) === -1) {
newShape[key] = this.shape[key];
} else {
const fieldSchema = this.shape[key];
let newField = fieldSchema;
while (newField instanceof ZodOptional) {
newField = (newField as ZodOptional<any>)._def.innerType;
}
newShape[key] = newField;
}
});
} else {
for (const key in this.shape) {
const fieldSchema = this.shape[key];
let newField = fieldSchema;
while (newField instanceof ZodOptional) {
newField = (newField as ZodOptional<any>)._def.innerType;
}

newShape[key] = newField;
newShape[key] = newField;
}
}
return new ZodObject({
...this._def,
Expand Down

0 comments on commit 4709160

Please sign in to comment.