Skip to content

Latest commit

 

History

History
106 lines (78 loc) · 3.52 KB

README.md

File metadata and controls

106 lines (78 loc) · 3.52 KB

A small type-safe object proxy around Zod to help you stay safe after your data is loaded.

Because it can be a bit verbose to modify and validate complex structures deeply after loading them.

If you don't need to modify your data after loading, you probably don't need zoxy!

Installation

pnpm add zod zoxy

Basic usage (live demo)

import { z } from 'zod';
import { zoxy } from 'zoxy';

const User = z.object({
  username: z.string().min(4),
  email: z.string().email().optional(),
  phone: z.object({
    home: z.string().min(10).max(42).optional(),
    work: z.string().min(10).max(42).optional(),
  }),
  foo: z.object({ bar: z.object({ baz: z.string().max(3).optional() }).optional() }).optional(),
});

const user = zoxy(User, { username: 'anonymous', phone: {} });

// Pass
user.username = 'nyan';
user.email = undefined;
user.phone.home = '555 042 42 42';
user.phone = { home: '555 042 42 42', work: '555 024 24 24' };

// Fail
user.email = 'xxx'; // throw 'Invalid email'
user.phone = { home: 'xxx' }; // throw 'String must contain at least 10 character(s)'

Ensure default value

In the example below the schema has three levels which are all optional and if you want to define the last level it can be quite verbose. Zoxy offers a solution to this with a little helper that makes sure that a default value is set. Simply prefix the desired value with a '$' sign and you get a method that allows you to set a default value.

const Data = z.object({
  foo: z
    .object({
      bar: z
        .object({
          baz: z.string().max(3).optional(),
        })
        .optional(),
    })
    .optional(),
});

const data = zoxy(Data, {});

// Get `data.foo.bar.baz` if defined or set default value where needed.
const baz = data.$foo({}).$bar({}).$baz('baz'); // 'baz'

The above line will perform the following actions:

  • if data.foo is undefined set it to {}
  • if data.foo.bar is undefined set it to {}
  • if data.foo.bar.baz is undefined set it to 'baz'
  • return data.foo.bar.baz

Note that the returned value can be something different from the default value if it has already been initialized previously.

Set deep optional property

If you want to assign a new value deeply you must use the following syntax.

// Set default value on `foo.bar` where needed and set `foo.bar.baz` to 'buzz'.
data.$foo({}).$bar({}).baz = 'buzz';

console.log(data.foo?.bar?.baz); // 'buzz'

Signature

function zoxy(schema: ZodObject, data: Data, options?: ZoxyOptions): Zoxy;

Options

type ZoxyOptions = {
  prefix: string; // default '$'
};

Scaffolded with @skarab/skaffold