Capítulo 38 de 61
Zod's docs publish a library of common codec recipes (string↔number, ISO datetime↔Date, bytes↔base64/hex, JSON parsing, etc.) as copy-paste-and-customize snippets rather than first-class APIs, since the "right" behavior (e.g. rounding, error format) is often project-specific.
stringToNumber (via parseFloat), stringToInt (via parseInt), stringToBigInt/numberToBigInt (via BigInt()).isoDatetimeToDate, epochSecondsToDate, epochMillisToDate — all wrap new Date(...) on decode and a matching serialization on encode.utf8ToBytes/bytesToUtf8 (via TextEncoder/TextDecoder), base64ToBytes, base64urlToBytes, hexToBytes (via Zod's own z.util.* byte-array helpers).stringToURL/stringToHttpURL (wrap the native URL constructor), uriComponent (wraps encodeURIComponent/decodeURIComponent).jsonCodec(schema): a factory (not a fixed codec) that parses a JSON string, validates the result against a caller-supplied schema, and reports malformed JSON as a proper invalid_format issue instead of an uncaught SyntaxError.// representative pattern: wrap a native conversion in decode/encode
const stringToInt = z.codec(z.string().regex(z.regexes.integer), z.int(), {
decode: (str) => Number.parseInt(str, 10),
encode: (num) => num.toString(),
});
// the generic JSON codec factory — reports parse errors as ZodError issues
const jsonCodec = <T extends z.core.$ZodType>(schema: T) =>
z.codec(z.string(), schema, {
decode: (jsonString, ctx) => {
try {
return JSON.parse(jsonString);
} catch (err) {
ctx.issues.push({ code: "invalid_format", format: "json", input: jsonString, message: err.message });
return z.NEVER;
}
},
encode: (value) => JSON.stringify(value),
});
const jsonToUser = jsonCodec(z.object({ name: z.string(), age: z.number() }));
jsonToUser.decode('{"name":"Alice","age":30}'); // => { name: "Alice", age: 30 }
decode, its inverse wrapped as encode — and the ctx.issues/z.NEVER pattern for turning a thrown error into a proper Zod issue.| Codec | Input schema | Output type | Core mechanism |
|---|---|---|---|
stringToNumber | z.string() (numeric regex) | number | parseFloat() |
stringToInt | z.string() (integer regex) | number (int) | parseInt(str, 10) |
stringToBigInt | z.string() | bigint | BigInt(str) |
numberToBigInt | z.int() | bigint | BigInt(num) |
isoDatetimeToDate | z.iso.datetime() | Date | new Date(isoString) |
epochSecondsToDate | z.int().min(0) | Date | new Date(seconds * 1000) |
epochMillisToDate | z.int().min(0) | Date | new Date(millis) |
utf8ToBytes / bytesToUtf8 | string / Uint8Array | the other | TextEncoder/TextDecoder |
base64ToBytes, base64urlToBytes, hexToBytes | format-specific string schema | Uint8Array | z.util.* byte-array helpers |
stringToURL / stringToHttpURL | z.url() / z.httpUrl() | URL | native URL constructor |
uriComponent | z.string() | z.string() | encodeURIComponent/decodeURIComponent |
jsonCodec(schema) | z.string() | whatever schema validates | JSON.parse/JSON.stringify, with parse errors reported as invalid_format issues |
jsonCodec() is the pattern to follow for wrapping any operation that can throw (JSON.parse) into a proper ctx.issues/z.NEVER failure instead of an uncaught exception.z.codec() API these recipes all build on.ctx.issues/z.NEVER is the same failure-reporting pattern used inside z.transform().