-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Allow generating an object with a full set of defaults that may not validate #213
Comments
I'm not clear on what you're asking for exactly. Can you provide some simpler examples of the behavior you want? |
Let me try simplifying the example above:
I know I could do something similar by simply not putting defaults in the schema and creating them in a separate object like:
I am checking to see if there is a way to avoid this and keep all the default value settings as part of the schema so a developer can go to one place to see the structure, validation checks, and default values for the configuration data structure. Does that make more sense? So effectively it is something like safeParser() but where it simply returns an object that is filled only with the default values but not validated. I know this is a bit of an odd use case, but I wanted to check if this is something that may already be supported by going through some hoops. |
This is definitely a tricky problem. I'm confused why this is z.string().nullable().default(null).refine(s => s != null && x.length > 5) This would work fine: z.string().nullable().default(null).refine(s => s ? x.length > 5 : true, "error") Then Other questions
Would it be enough to have an option to disable refinement checks during parsing? This doesn't disable all typechecking, just the |
The reason for the null is the tricky part. Basically there are some configuration items that don't have a default so I set them to null or undefined. Then the user in their configuration file has to define them. The "has to" would get enforced by the refine() call and the safeParse() to ensure that we have a valid configuration. So in pure typescript I would be doing:
If a key didn't have a default then I would expect it to default to undefined, but in my case I would give them all defaults. As far as nested keys, it would definitely need to support nested objects. The configuration object I am using is 2-3 levels deep with configuration settings. To your question about disabling refinement checks during parsing, that could be interesting. I was actually thinking just a way to extract a copy of anything that has a default. Maybe a helper function that recurses through the schema looking for defaults and adding them into an object that is returned. |
Gotcha, I understand now. The simple answer is that this isn't possible currently. You can't have a schema that will accept You basically need a validator that is able to behave differently depending on the context. In your case you want slightly different behavior depending on whether you're generating the defaults or parsing the final config object. This concept is discussed here: #84 Fortunately JavaScript gives you everything to need to implement this: closures. It's a very advanced pattern but it's really powerful. Here's what I came up with: const getSettingsSchema = (mode: 'input' | 'output') => {
const setDefaultByMode = <T extends z.ZodTypeAny>(
schema: T,
defaultValue: T['_type'] | null,
) => {
return mode === 'input' ? schema.nullable().default(defaultValue) : schema;
};
return z.object({
name: setDefaultByMode(z.string(), 'DEFAULT'),
nested: z
.object({
inner: setDefaultByMode(z.number(), null),
})
.default({}),
});
};
const inputTest = getSettingsSchema('input');
const outputTest = getSettingsSchema('output');
const defaults = inputTest.parse({});
// => { name: 'DEFAULT', nested: { inner: null } }
console.log(outputTest.parse(defaults));
/*
Error: [
{
"code": "invalid_type",
"expected": "number",
"received": "null",
"path": [
"nested",
"inner"
],
"message": "Expected number, received null"
}
]
*/ You define your schema inside a function that accepts a single string argument (the This fixes the problem where you were making all your schemas |
@vriad That is brilliant!! Thank you so much for that idea. I think I have what I need to try it out. I think we can close this out for now and I will work with this pattern. |
Ran into one interesting issues. This pattern works to build up the schema, but the type of the schema returned by getSettingSchema includes the nullable. So if I try to infer the strict schema into a typescript type it still has the nulls involved.
I can probably still make this workable but would be great to find a way to infer the correct typescript type. |
I am looking to use zod as a way to validate user configuration files for a command line utility. It looks like a great fit compared to what we are doing now, but I am having trouble with one aspect.
The workflow we use is:
My problem is that in this model I don't see a way to use zod to create the initial defaults object. I know I could create it as a plain old javascript object separate from the schema, but I was hoping to take advantage of the .default() methods within the schema to have the schema be self describing without having a separate large defaults object.
So my hope was to make something like this work:
Is anything like this possible or practical as a feature in zod? I think it is effectively a SafeParse that doesn't do any checks, but instead just sets the default values on the object passed in.
The text was updated successfully, but these errors were encountered: