sveltekit-superforms: Nested objects defaults not working/Nested Errors are flattened into an array of strings
Thanks for the great module, I’m a bit new so not sure if this is a superforms issue or a zod issue but, I have the following types:
If there are validation issues on the ListingProject (which is a nested zod object), the errors show up as [error1, error2, error3] so in the form it’s a bit difficult to show the error on the nested object.
Plus I assumed that superforms assumes the defaults based on the object type, for the ListingProject object, there’s a couple of fields that are arrays of strings or objects, when trying to build forms that use these fields you get "cannot read attribute of undefined (reading length).
so what I do is in the nested object definition I put .default({ array1: [], array2: []} is this the best way to go about it?
Thanks for the great work!
import { z } from 'zod';
export const SocialNetworks = z.enum([
'twitter',
'discord',
'telegram',
'facebook',
'instagram',
'others'
]);
const SocialData = z.object({
network: SocialNetworks,
handle: z.string().min(1).max(100),
members: z.number().min(0)
});
export type ListingType = z.infer<typeof Listing>;
export const ProjectTypes = ['NFT', 'DeFi', 'DAO', 'DEX', 'Games', 'Others'];
export const ListingProject = z.object({
name: z.string().min(1).max(100),
helloMoonCollectionId: z
.string()
.min(1)
.max(50)
// .optional()
.default('040de757c0d2b75dcee999ddd47689c4'),
collectionName: z.string().min(1).max(100),
launchDate: z.date(),
launchPrice: z.number().min(0),
socials: z.record(SocialData).default({}),
links: z.record(z.string().url()),
floorPriceAtListing: z.number().min(0),
listingsAtListing: z.number().min(0),
volumeAtListing: z.number().min(0),
ownersAtListing: z.number().min(0),
supply: z.number().min(1),
description: z.string().min(1).max(500),
image: z.string().url(),
website: z.string().url(),
categories: z.array(z.enum(ProjectTypes)).default([]),
network: z
.enum(['Solana', 'Ethereum', 'Binance Smart Chain', 'Polygon', 'Solana', 'Others'])
.default('Solana')
});
export const ProjectAddressTypes = z.nativeEnum({
royalty: 'Royalty',
treasury: 'Treasury',
creatorAddress: 'Creator Address',
updateAuthority: 'Update Authority',
mintAuthority: 'Mint Authority',
freezeAuthority: 'Freeze Authority',
claimAuthority: 'Claim Authority',
others: 'Others'
});
export const ProjectAddress = z.object({
network: z.enum(['Solana', 'Ethereum', 'Binance Smart Chain', 'Polygon', 'Solana', 'Others']),
address: z.string().min(1).max(100),
balance: z.number().min(0).optional(),
type: ProjectAddressTypes,
note: z.string().min(1).max(100)
});
const ProjectFinancials = z.object({
// item
item: z.string().min(1).max(100),
// item value
value: z.number().min(0),
// item value unit
unit: z.enum(['SOL', 'USD', 'ETH', 'BNB', 'MATIC', 'others']).default('SOL')
});
export const TechStackItem = z.object({
name: z.string().min(1).max(100),
description: z.string().min(1).max(1000),
type: z.enum(['backend', 'frontend', 'database', 'others']),
url: z.string().url(),
technology: z.string().min(1).max(100),
version: z.string().min(1).max(100).default('latest')
});
export enum ListingPurpose {
takeoverFull = 'takeoverFull',
takeoverPartial = 'takeoverPartial',
funding = 'funding',
others = 'others'
}
export const PricingUnits = ['SOL', 'USD', 'ETH', 'BNB', 'MATIC'];
export const ListingPurposes = z.enum(['takeoverFull', 'takeoverPartial', 'funding', 'others']);
export const Listing = z.object({
id: z.string().uuid(),
user: z.string().min(1).max(50),
created: z.date().default(() => new Date()),
updated: z.date().nullable(),
financials: ProjectFinancials,
techStack: z.array(TechStackItem),
project: ListingProject.default({ socials: {}, network: 'Solana', categories: [] }),
headline: z.string().min(1).max(100),
reason: z.string().min(1).max(1000),
// purpose options ['takeover-full', 'takeover-partial', 'funding', 'others'] array
purpose: z.array(ListingPurposes),
partialTakeoverPercentage: z.number().min(0).max(100).optional(),
overview: z.string().min(1).max(1000),
addresses: z.array(ProjectAddress),
price: z.number(),
priceUnit: z.enum(PricingUnits).default('SOL'),
priceIncludes: z.array(z.string().min(1).max(100)),
type: z.enum(['auction', 'fixedPrice', 'others']).default('fixedPrice')
});
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 29 (17 by maintainers)
@teenjuna and @Bewinxed maybe you can give some feedback on the nested error structure I have in mind for 0.6.0. It’s a slight rewrite of the Zod structure:
Given this schema:
An error structure like this can be the result:
This means that the top-level error handling is still the same, and if you have a nested object, you’re sure to be aware of that, and have to use the other syntax. And maybe the same can be done with constraints. What do you think?
Ouch! I hope the Zod inference can be of help to avoid that level of complication…
Yeah, supporting this with a good TS experience will result in some type witchcraft. Just looks at the code of
felte: https://github.com/pablo-abc/felte/blob/main/packages/common/src/types.ts