Skip to content

Commit

Permalink
Fixes falsy default value issue
Browse files Browse the repository at this point in the history
  • Loading branch information
Colin McDonnell committed Sep 27, 2020
1 parent c35fe04 commit c87fe1c
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -1596,7 +1596,7 @@ const stringWithDefault = z.transformer(
);
```

Equivalently you can express this using the built-in `.default()` method, available on all Zod schemas. A default value will be used if the schema is `null` or `undefined`.
Equivalently you can express this using the built-in `.default()` method, available on all Zod schemas. The default value will be used if and only if the schema is `undefined`.

```ts
z.string().default('default value');
Expand Down
19 changes: 12 additions & 7 deletions src/__tests__/transformer.test.ts
Expand Up @@ -60,20 +60,25 @@ test('default', () => {
});

test('default when property is null or undefined', () => {
const data = z.object({
foo: z.boolean().nullable().default(true),
bar: z.boolean().default(true)
}).parse({ foo: null });
const data = z
.object({
foo: z
.boolean()
.nullable()
.default(true),
bar: z.boolean().default(true),
})
.parse({ foo: null });

expect(data).toEqual({ foo: true, bar: true });
expect(data).toEqual({ foo: null, bar: true });
});

test('default with falsy values', () => {
const schema = z.object({
emptyStr: z.string().default('def'),
zero: z.number().default(5),
falseBoolean: z.boolean().default(true)
})
falseBoolean: z.boolean().default(true),
});
const input = { emptyStr: '', zero: 0, falseBoolean: true };
const output = schema.parse(input);
// defaults are not supposed to be used
Expand Down
28 changes: 15 additions & 13 deletions src/parser.ts
Expand Up @@ -375,20 +375,22 @@ export const ZodParser = (schema: z.ZodType<any>) => (
if (!keyValidator) continue;

// check if schema and value are both optional
try {
keyValidator.parse(undefined, {
...params,
path: [...params.path, key],
});

// const keyDataType = getParsedType(data[key]);
if (!Object.keys(data).includes(key)) {
// schema is optional
// data is undefined
// don't explicity add undefined to outut
continue;
}
} catch (err) {}
// const keyDataType = getParsedType(data[key]);
if (!Object.keys(data).includes(key)) {
try {
const output = keyValidator.parse(undefined, {
...params,
path: [...params.path, key],
});
if (output === undefined) {
// schema is optional
// data is undefined
// don't explicity add undefined to outut
continue;
}
} catch (err) {}
}

objectPromises[key] = new PseudoPromise().then(() => {
try {
Expand Down
22 changes: 11 additions & 11 deletions src/playground.ts
@@ -1,17 +1,17 @@
import * as z from '.';

const run = async () => {
const SNamedEntity = z.object({
id: z.string(),
set: z.string().optional(),
unset: z.string().optional(),
});
const result = await SNamedEntity.parse({
id: 'asdf',
set: undefined,
});
console.log(result);
console.log(Object.keys(result));
const data = z
.object({
foo: z
.boolean()
.nullable()
.default(true),
bar: z.boolean().default(true),
})
.parse({ foo: null });

console.log(data);
};
run();

Expand Down
2 changes: 1 addition & 1 deletion src/types/base.ts
Expand Up @@ -324,7 +324,7 @@ export abstract class ZodType<
def: T,
) => ZodTransformer<Opt, this> = def => {
return ZodTransformer.create(this.optional(), this, (x: any) => {
return (x ?? def) as any;
return x === undefined ? def : x;
}) as any;
};

Expand Down

0 comments on commit c87fe1c

Please sign in to comment.