Describe the feature
Currently, the plugin generates .nullish() for optional GraphQL fields when using schema: "zodv4". However, in some projects, .nullable() is preferred over .nullish().
I'd like to propose a new configuration option that allows developers to control this behavior.
Proposed solution
Add a new config option nullishBehavior (or similar) that accepts:
"nullish" (default) — generates .nullish() for optional fields
"nullable" — generates .nullable() for optional fields
"optional" — generates .optional() for optional fields (only undefined, no null)
Example configuration:
generates:
path/to/schemas.ts:
plugins:
- typescript-validation-schema
config:
schema: zodv4
nullishBehavior: nullable # or "nullish" (default), or "optional"
Current behavior (nullish):
// GraphQL: field: String
// Generated:
field: z.string().nullish() // allows null | undefined
Desired behavior (nullable):
// GraphQL: field: String
// Generated:
field: z.string().nullable() // allows null only
Use case:
Our project's GraphQL API treats optional fields as nullable but not undefined in the response. Using .nullish() generates types that are too permissive (string | null | undefined) and doesn't match our actual API contract (string | null).
Current workaround:
We're using a post-generation script to replace .nullish() with .nullable():
// scripts/fix-nullish.ts
import fs from "fs";
import path from "path";
const TARGET_FILE = "schemas.generated.ts";
const NULLISH_PATTERN = /\.nullish\(\)/g;
const schemaFile = process.argv
.slice(2)
.find((file) => file.includes(TARGET_FILE));
if (!schemaFile) {
console.warn(`⏭️ ${TARGET_FILE} was not passed to the script`);
process.exit(0);
}
const fullPath = path.resolve(process.cwd(), schemaFile);
if (!fs.existsSync(fullPath)) {
console.error(`❌ File not found: ${fullPath}`);
process.exit(1);
}
const content = fs.readFileSync(fullPath, "utf-8");
const updated = content.replace(NULLISH_PATTERN, ".nullable()");
if (content === updated) {
console.warn(`ℹ️ No nullish() found to replace in ${schemaFile}`);
process.exit(0);
}
fs.writeFileSync(fullPath, updated);
console.warn(`✅ Replaced nullish() with nullable() in ${schemaFile}`);
// codegen.ts
hooks: {
afterOneFileWrite: ["npx tsx scripts/fix-nullish.ts"]
}
While this works, it would be much cleaner to have this as a built-in configuration option.
Additional context:
Thank you for considering this feature!
Describe the feature
Currently, the plugin generates
.nullish()for optional GraphQL fields when usingschema: "zodv4". However, in some projects,.nullable()is preferred over.nullish().I'd like to propose a new configuration option that allows developers to control this behavior.
Proposed solution
Add a new config option
nullishBehavior(or similar) that accepts:"nullish"(default) — generates.nullish()for optional fields"nullable"— generates.nullable()for optional fields"optional"— generates.optional()for optional fields (onlyundefined, nonull)Example configuration:
Current behavior (nullish):
Desired behavior (nullable):
Use case:
Our project's GraphQL API treats optional fields as nullable but not undefined in the response. Using
.nullish()generates types that are too permissive(string | null | undefined)and doesn't match our actual API contract(string | null).Current workaround:
We're using a post-generation script to replace .nullish() with .nullable():
While this works, it would be much cleaner to have this as a built-in configuration option.
Additional context:
This is specifically relevant for schema: "zodv4"
Similar issue has been discussed in Optional properties become required in inferred Zod v4 schema types #1362 regarding optional properties becoming required
Other validation libraries like yup have .nullable() vs .required() distinction
Thank you for considering this feature!