README.md
exact-mirror-zod
AOT compiler for Zod 4 schemas that generates fast property-stripping functions. Port of exact-mirror from TypeBox to Zod 4.
Install
bash
| 1 | bun add exact-mirror-zod |
Requires Zod 4.
Usage
typescript
| 1 | import { z } from "zod"; |
| 2 | import { createMirror } from "exact-mirror-zod"; |
| 3 | |
| 4 | const schema = z.object({ name: z.string(), age: z.number() }); |
| 5 | const mirror = createMirror(schema); |
| 6 | |
| 7 | mirror({ name: "test", age: 25, password: "leaked" }); |
| 8 | // => { name: "test", age: 25 } |
createMirror(schema) compiles a Zod schema into a function that strips unknown properties from objects to match the schema's shape. It does not validate -- it assumes input is already valid and just projects known keys.
Why?
Validate on input (z.parse()), strip on output (createMirror()). Prevents leaking internal fields from API responses without the overhead of full re-parsing. Typically 5-15x faster than z.parse() for stripping.
Supported Types
| Type | Behavior |
|---|---|
| Object | Keeps only declared keys |
| Array | Per-element mirroring (passes through primitive arrays) |
| Tuple | Per-index mirroring |
| Record | Object.keys iteration with value mirroring |
| Discriminated Union | switch on discriminator key |
| Union | Cheap typeof / Array.isArray structural checks |
| Intersection | Merges object shapes |
Recursive (z.lazy) | Memoized helpers with cycle detection |
| Wrappers | optional, nullable, default, readonly, branded, pipe -- unwraps and recurses |
Options
typescript
| 1 | createMirror(schema, { |
| 2 | // Sanitization functions applied to every string value |
| 3 | sanitize: (v) => v.trim(), |
| 4 | |
| 5 | // Max recursion depth for z.lazy() schemas (default: 8) |
| 6 | recursionLimit: 8, |
| 7 | |
| 8 | // Remove values that don't match any union variant (default: false) |
| 9 | removeUnknownUnionType: false, |
| 10 | }); |
String Sanitization
Pass one or more functions to transform every string value in the output:
typescript
| 1 | const mirror = createMirror(schema, { |
| 2 | sanitize: [(v) => v.trim(), (v) => v.replace(/</g, "<")], |
| 3 | }); |
Development
bash
| 1 | bun test # run tests |
| 2 | bun run bench # run benchmarks |
| 3 | bun run bench:small # benchmark small schemas |
| 4 | bun run bench:compare # compare against z.parse() |
| 5 | bun run typecheck # type check |
| 6 | bun run fix # lint + format |
License
MIT