https://github.com/jcoreio/zod-invertible
declare zod schemas that can be inverted to format from output to input
https://github.com/jcoreio/zod-invertible
Last synced: 2 months ago
JSON representation
declare zod schemas that can be inverted to format from output to input
- Host: GitHub
- URL: https://github.com/jcoreio/zod-invertible
- Owner: jcoreio
- License: mit
- Created: 2024-07-08T19:54:47.000Z (almost 2 years ago)
- Default Branch: master
- Last Pushed: 2025-05-21T19:41:00.000Z (about 1 year ago)
- Last Synced: 2025-06-27T05:42:00.053Z (12 months ago)
- Language: TypeScript
- Homepage:
- Size: 107 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# zod-invertible
declare zod schemas that can be inverted to format from output to input
[](https://circleci.com/gh/jcoreio/zod-invertible)
[](https://codecov.io/gh/jcoreio/zod-invertible)
[](https://github.com/semantic-release/semantic-release)
[](http://commitizen.github.io/cz-cli/)
[](https://badge.fury.io/js/zod-invertible)
# Limitations and notes
`zod-invertible` doesn't support the following schemas, and `invert` will throw an error if it encounters them:
- `z.preprocess(...)`
- `ZodType.transform(...)` (outside of the transform created by `invertible`)
However, you may work around this by marking the schema with `ignoreEffect`:
```ts
import { schema, ignoreEffect } from 'zod-intervible'
const innerSchema = ...
const schema = ignoreEffect(z.preprocess((value) => ..., innerSchema))
const inverse = invert(schema) // equivalent to invert(innerSchema)
```
The inverse of `ZodType.default(...)` will not have a default, which should be okay, since the input to the inverse should
always be defined.
The inverse of `ZodType.catch(...)` will not catch. If you want to use a fallback value if errors are thrown during parsing or
formatting, add your own logic in the `parse` and `format` functions you pass to `invertible`.
If the output types of `z.union([...])` options overlap, then `invert(z.union([...])).parse(output)` may format with a
different union option than the one that parsed the input.
If you have recursive schemas (using `z.lazy()`), the inverse `z.lazy()` schemas will re-invert the resolved schema each time
they are used. I may fix this in the future with a `WeakMap` inverse cache.
# Example
```sh
npm i zod-invertible
# OR
pnpm i zod-invertible
```
```ts
import z from 'zod'
import { invertible, invert, ZodInvertible } from 'zod-intertible'
const StringToNumber = invertible(
z.string(),
(s, ctx) => {
const result = parseFloat(s)
if (isNaN(result)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'invalid float',
})
}
return result
},
z.number(),
(n) => String(n)
)
StringToNumber instanceof ZodInvertible // true
StringToNumber.parse('3.5') // 3.5
const NumberToString = invert(StringToNumber)
NumberToString.parse(3.5) // '3.5'
const obj = z.object({ foo: StringToNumber })
obj.parse({ foo: '3.5' }) // { foo: 3.5 }
// invert works deeply:
invert(obj).parse({ foo: 3.5 }) // { foo: '3.5' }
```
## `invertible(inputSchema, parse, outputSchema, format)`
Creates an invertible schema that transforms from an input type to a different output type.
Returns a `ZodInvertible`, which is a subclass of `ZodPipeline`.
### `inputSchema`
The `ZodType` for validating the input value
### `parse`
The function for transforming the input value into the output value. It is called with two arguments:
- `value`: the output of `inputSchema`
- `ctx`: the zod `RefinementCtx`
`parse` may be `async`.
### `outputSchema`
The `ZodType` for validating the output
### `format`
The function for converting from the output value back into the input value. It is called with two arguments:
- `value`: the input of `outputSchema`
- `ctx`: the zod `RefinementCtx`
`format` may be `async`.
## `invert(schema)`
Deeply inverts a zod schema, inverting any `ZodInvertible` schemas inside it, and otherwise preserving the structure of
objects, arrays, etc.
If the zod schema parses input type `I` into output type `O`, the inverted schema will parse input type `O` into output type `I`.