Primate LogoPrimate

Objects

Prefer callable p({...}) to create an object schema. The explicit p.object({...}) factory is equivalent and remains available for completeness. Nested schema shorthand is normalized recursively.

const User = p({
  name: p.string,
  settings: {
    alerts: p.boolean.default(true),
  },
});

ObjectType exposes properties, its inferred input, optional(), extend(), shape<T>(), closed() and min().

Unknown properties

Objects discard undeclared input properties by default:

p({ name: p.string }).parse({ name: "Ada", admin: true });
// { name: "Ada" }

Closed objects

Use closed() to reject them instead:

const User = p({ name: p.string }).closed();
User.parse({ name: "Ada", admin: true });
// unknown_property at /admin

The issue path is an escaped JSON Pointer. Closing is local: nested object schemas remain open unless they also call closed(). This policy is unrelated to p.strict, which controls coercion.

Minimum supplied properties

Object min(n) requires at least n supplied, declared properties to parse successfully. A property counts only when it is an own enumerable input property and its raw value is not undefined. Unknown fields and values created only by defaults do not count.

const Patch = p({
  name: p.string.optional(),
  enabled: p.boolean.default(true),
}).min(1);

Patch.parse({});              // too_small
Patch.parse({ name: "Ada" }); // valid

The bound must be a finite, nonnegative integer.

Partial updates

p.partial(shape) makes every declared property optional without changing its validator. It accepts a property map or an ObjectType.

const User = {
  name: p.string,
  email: p.string.email(),
};

const UpdateUser = p.partial(User).closed().min(1);

This pattern rejects empty updates and misspelled fields. PartialType also supports default(), derive(), closed() and min().

Extend, shape and omit

extend() adds nonconflicting properties. Policies belong to the receiver:

const Base = p({ id: p.u32 }).closed();
const User = Base.extend({ name: p.string });

The result remains closed. If the extension argument is another object schema, only its properties are imported, not its closed or min policies.

shape<T>() aliases the inferred output type while preserving runtime parsing; it does not add runtime validation. p.omit(schema, ...keys) creates an OmitType without the named properties:

const PublicUser = p.omit(User, "id");

Async objects

p.async(shape) creates an AsyncType for object parsing followed by async derivation:

const Account = p.async({ id: p.string })
  .derive(async ({ id }) => await loadAccount(id));

const account = await Account.parse({ id: "ada" });

Async schemas expose parse(), derive(), infer, input, schema and properties. They are useful as Primate route body and path schemas, but are validation-only and not direct Store fields.

See Errors for object issue paths and Input validation for route integration.