Allow null to be treated as not-present for optional fields
Request a feature
(Related to https://github.com/arktypeio/arktype/issues/1191)
I wish to be able to have a type with an optional non-null field that accepts null as being equivalent to not present:
import { scope } from "arktype";
export const mod = scope({
Model: {
"field?": "number.integer",
other: "string",
},
});
export const types = mod.export();
export const Model = types.Model;
// should not give an error
console.log(Model(JSON.parse('{"other": "hi", "field": null}')).summary);
🤷 Motivation
I use arktype models to validate data produced by pydantic models. Optional fields in pydantic are, by default, emitted as "field": null when JSON encoded. I wish to have typescript types and validations that accept "field": null as if it were absent from the JSON. It is undesirable to have the field defined as number.intger | null as it adds extra complexity to consumption code.
For this use-case undefined is not an option as it cannot be JSON serialised.
💡 Solution
I am not sure what the best interface would look like, but perhaps a field specified as e.g "field?": "number.integer?" could behave in this way? or a global config, or a mode that applies specifically to JSON parsing?
Not sure exactly what the solution will look like yet either, but I want to build something general here that allows certain types to be treated as if they weren't present as opposed to just special-casing null.
For example, devs working with forms may also want an empty string to be treated as not present.
+1
I'd love to be able to write type.string.optional({ nullable: true }) or something like this, that normalizes null | undefined to undefined.
status: type.string.or(type.null.pipe(() => undefined)).optional(), seems to be a bit long, also the resulting types doesn't look nice.
@plehnen thank you for the suggestion of using pipe as an intermediate solution. It was on my todo list to investigate this, so you've just saved me some effort 😄
For now I shall use the following form, but I still see significant value in formal support.
Model: {
"field?": type("number.integer").or(type.null.pipe(() => undefined)),
other: "string",
},
I'd be happy if I could just configure the decoding more tolerant, rather than loosening the entire type constraint in the model.