colinhacks / zod

TypeScript-first schema validation with static type inference
https://zod.dev
MIT License
32.58k stars 1.13k forks source link

ZodReadonly missing methods to manipulate schema shape #3577

Open ravinggenius opened 2 months ago

ravinggenius commented 2 months ago

Several methods for manipulating the shape of a schema are conspicuously missing just by marking a schema as read-only:

import { z } from "zod";

export const EDITION = z.enum(["bedrock", "java"]);

export const VERSION = z.object({
    id: z.string().uuid(),
    createdAt: z.coerce.date(),
    updatedAt: z.coerce.date(),
    edition: EDITION,
    version: z.string(),
    cycle: z.tuple([z.number().nonnegative(), z.number().nonnegative()]),
    releasedOn: z.coerce.date(),
    releaseNotesUrl: z.string().url(),
    isPublished: z.boolean().default(false).optional()
});

export const LATEST_VERSION = VERSION.extend({
    isLatest: z.boolean(),
    isLatestInCycle: z.boolean()
}).readonly();

export const RARITY = z.enum(["common", "uncommon", "rare", "epic"]);

export const ITEM = z.object({
    id: z.string().uuid(),
    createdAt: z.coerce.date(),
    updatedAt: z.coerce.date(),
    identity: z.string(),
    wikiUrl: z.string().url(),
    rarity: RARITY.default("common").optional(),
    stackSize: z.number().positive().default(64).optional(),
    isRenewable: z.boolean()
});

export const VERSIONED_ITEM = ITEM.and(
    z.object({
        // unrelated, but if there's a better way to rename a property, i'd like to know
        versionId: LATEST_VERSION.shape.id // .shape isn't available because LATEST_VERSION is read-only
    })
)
    .and(
        LATEST_VERSION.pick({ // .pick() isn't available because LATEST_VERSION is read-only
            edition: true,
            version: true,
            cycle: true,
            isLatest: true,
            isLatestInCycle: true
        })
    )
    .readonly();

Everything is fine if I remove .readonly() from LATEST_VERSION and VERSIONED_ITEM. However these schemas represent views in the database, so they are inherently read-only. Shouldn't we be able to mark schemas as read-only and still be able to use helpers like .pick(), .omit() and .shape?


Edit: formatting

ravinggenius commented 2 months ago

I verified I'm using the latest version (zod@3.23.8). I didn't check for any pre-release version or anything though. I did take a quick look through the source code, and I didn't see anything on the main branch that indicated these methods were available for ZodReadonly schemas.