typescript - Egenskapen 'shape' finns inte på typen i Zod?
Jag gör detta i Zod:
export const LoadSort: z.ZodType<LoadSort> = z.object({
name: z.string(),
tilt: z.enum(['+', '-']),
})
console.log(LoadSort.shape)
Men får ett fel på .shape:
Egenskapen 'shape' finns inte på typen 'ZodType
'.ts(2339)
Faktiskt är min kod mer komplex och kräver att jag använder icke-avledda typer. Här är min fullständiga kod
import { z } from 'zod'
export const LOAD_FIND_TEST = [
'bond',
'base_link_mark',
'head_link_mark',
'base_mark',
'head_mark',
'base_text',
'miss_bond',
'have_bond',
'have_text',
] as const
export type Load = {
find?: LoadFind
read?: LoadRead
save?: LoadSave
task?: string
}
export type LoadFind = LoadFindLink | Array<LoadFindLink>
export type LoadFindBind = {
form: 'bind'
list: Array<LoadFindLink>
}
export type LoadFindLike = {
base: LoadFindLikeLinkBond
form: 'like'
head: LoadFindLikeBond | LoadFindLikeLinkBond
test: LoadFindTest
}
export type LoadFindLikeBond = string | boolean | null | number
export type LoadFindLikeLinkBond = {
link: string
}
export type LoadFindLink = LoadFindLike | LoadFindRoll | LoadFindBind
export type LoadFindRoll = {
form: 'roll'
list: Array<LoadFindLink>
}
export type LoadFindTest = (typeof LOAD_FIND_TEST)[number]
export type LoadRead = {
[key: string]: true | LoadReadLink
}
export type LoadReadLink = {
find?: LoadFind
read: LoadRead
}
export type LoadSave = {
[key: string]: Array<LoadSaveBase> | LoadSaveBase
}
export type LoadSaveBase = {
find?: LoadFind
read?: LoadRead
save?: LoadSave
task?: string
}
export type LoadSort = {
name: string
tilt: '+' | '-'
}
export const Load: z.ZodType<Load> = z.object({
find: z.optional(z.lazy(() => LoadFind)),
read: z.optional(z.lazy(() => LoadRead)),
save: z.optional(z.lazy(() => LoadSave)),
task: z.optional(z.string()),
})
export const LoadFind: z.ZodType<LoadFind> = z.union([
z.lazy(() => LoadFindLink),
z.array(z.lazy(() => LoadFindLink)),
])
export const LoadRead: z.ZodType<LoadRead> = z.record(
z.union([z.lazy(() => LoadReadLink), z.literal(true)]),
)
export const LoadSave: z.ZodType<LoadSave> = z.record(
z.union(
z.array(z.lazy(() => LoadSaveBase)),
z.lazy(() => LoadSaveBase),
),
)
export const LoadFindBind: z.ZodType<LoadFindBind> = z.object({
form: z.literal('bind'),
list: z.array(z.lazy(() => LoadFindLink)),
})
export const LoadFindRoll: z.ZodType<LoadFindRoll> = z.object({
form: z.literal('roll'),
list: z.lazy(() => z.array(LoadFindLink)),
})
export const LoadFindTest = z.enum([
'bond',
'base_link_mark',
'head_link_mark',
'base_mark',
'head_mark',
'base_text',
'miss_bond',
'have_bond',
'have_text',
])
export const LoadFindLike: z.ZodType<LoadFindLike> = z.object({
base: z.lazy(() => LoadFindLikeLinkBond),
form: z.literal('like'),
head: z.union([
z.lazy(() => LoadFindLikeLinkBond),
z.lazy(() => LoadFindLikeBond),
]),
test: LoadFindTest,
})
export const LoadFindLink: z.ZodType<LoadFindLink> = z.union([
z.lazy(() => LoadFindLike),
z.lazy(() => LoadFindRoll),
z.lazy(() => LoadFindBind),
])
export const LoadFindLikeBond: z.ZodType<LoadFindLikeBond> = z.union([
z.string(),
z.boolean(),
z.null(),
z.number(),
])
export const LoadFindLikeLinkBond: z.ZodType<LoadFindLikeLinkBond> =
z.object({
link: z.string(),
})
export const LoadReadLink: z.ZodType<LoadReadLink> = z.object({
find: z.optional(LoadFind),
read: LoadRead,
})
export const LoadSaveBase: z.ZodType<LoadSaveBase> = z.object({
find: z.optional(LoadFind),
read: z.optional(LoadRead),
save: z.optional(LoadSave),
task: z.optional(z.string()),
})
export const LoadSort: z.ZodType<LoadSort> = z.object({
name: z.string(),
tilt: z.enum(['+', '-']),
})
Hur anger jag både ZodType och samtidigt fortfarande få tillgång till alla egenskaper som .shape som finns på det härledda objektet?
Jag kan på något sätt få det att fungera med det här tricket, men det verkar inte riktigt rätt:
export const LoadSort: z.ZodType<LoadSort> = z.object({
name: z.string(),
tilt: z.enum(['+', '-']),
})
assertZodObject(LoadSort)
for (const name in LoadSort.shape) {
const def = LoadSort.shape[name] as z.ZodType
console.log(def)
}
export function assertZodObject<S extends z.ZodObject<z.ZodRawShape>>(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
x: any,
): asserts x is S {
if (!(x instanceof z.ZodObject)) {
throw new Error()
}
}
Svar #1
Eftersom du anger att LoadSort (variabeln) är z.ZodType<LoadSort>, och .shape-egenskapen finns i ZodObject, inte i ZodType.
För att komma åt .shape-egenskapen och behålla schematypkontroll, försök använda satisfies-nyckelordet:
const LoadSort = z.object({
name: z.string(),
tilt: z.enum(['+', '-']),
}) satisfies z.ZodType<LoadSort>
Orelaterat: använd inte samma namn på variabel och gränssnitt, det kan förväxlas.
Svar #2
Jag fann att detta fungerar (lite annorlunda fall med .refine(), men kan vara användbart för folk som hittar detta):
Ta bara bort det extra skrivandet och exportera formen separat så här: (.refine() ändrar typen)
export const mySchema = z.object({ email: z... }).refine(...)
// Access the underlying parent schema with `._def` that refine() gives you
export const schemaShape = mySchema.sourceType()._def.shape()
