Shouldn't z.input for templateLiteral be string?
I was trying this today:
const schema = z.templateLiteral(["0x", z.string()]).default("0x")
And I was expecting that alongside z.input I could pass like an env var to it
const value: z.input<typeof schema> = process.env.PRIVATE_KEY
But it doesn't work because the z.input for templateLiteral is the same as the output type.
I'm not sure if this is expected or not, but it was counter-intuitive for me.
(For reference, we use Zod a lot to parse env variables into config objects where we want to at least validate that the "shape" is correct, that is, the keys are correct and that the fields are strings).
Hi @bamorim! I'm Dosu and I’m helping the zod team.
You're right—z.input for z.templateLiteral is the same as the output type, not just string. This is intentional in Zod's design: the input and output types for template literal schemas are both set to the template literal type, so TypeScript expects the input to already match the template literal pattern, not just be any string. This can feel counter-intuitive, especially when working with environment variables, which are always strings and may not match the template literal type at the type level even if they do at runtime (source).
A common workaround is to use z.string().regex(...) and then cast the schema to the desired template literal type, or use z.preprocess to coerce the input. For example:
const schema = z.preprocess(
(val) => (typeof val === "string" ? val : ""),
z.templateLiteral(["0x", z.string()]).default("0x")
);
This way, you can safely assign process.env.PRIVATE_KEY to z.input<typeof schema>, and Zod will handle the runtime validation.
If this answers your question, feel free to close the issue! If you have more questions or want to discuss further, just let me know.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other