Add passthrough object schema
vladshcherbin opened this issue · comments
Hey 👋
I'm porting my projects to use valibot
instead of zod
and would love to have some kind of passthrough object schema.
My use case:
I'm validating API requests with lots of nested objects and want to keep unknown props while validating the ones in schema.
With rest
object param I can do it this way:
object({ location: string() }, unknown())
It works great.
However with nested objects it becomes hard to track this objects, for example:
Nested object example
const schema = object({
adverts: array(
object({
id: number(),
locationName: string(),
metadata: object({
brandId: number(),
modelId: number()
}, unknown()),
photos: array(
object({
big: object({
height: number(),
url: string([url()]),
width: number()
}, unknown()),
main: boolean(),
mimeType: picklist(['image/jpeg', 'image/png'])
}, unknown())
),
price: object({
usd: object({
amountFiat: number(),
currency: literal('usd')
}, unknown())
}, unknown()),
properties: array(
object({
name: string(),
value: union([boolean(), number(), string()])
}, unknown()),
[minLength(1)]
),
publicUrl: string([url()]),
year: number()
}, unknown())
),
currentSorting: object({
label: literal('новые объявления')
}),
pageCount: number()
}, unknown())
For me it's quite hard to track such objects, check any missing unknown()
rest types, add new objects 😢
zod
has passthrough()
method with pending feature request to have global method.
Feature request
Imagine having a simple type for this in valibot
. Just compare:
Proposed api example
const schema = passthroughObject({
adverts: array(
passthroughObject({
id: number(),
locationName: string(),
metadata: passthroughObject({
brandId: number(),
modelId: number()
}),
photos: array(
passthroughObject({
big: passthroughObject({
height: number(),
url: string([url()]),
width: number()
}),
main: boolean(),
mimeType: picklist(['image/jpeg', 'image/png'])
})
),
price: passthroughObject({
usd: passthroughObject({
amountFiat: number(),
currency: literal('usd')
})
}),
properties: array(
passthroughObject({
name: string(),
value: union([boolean(), number(), string()])
}),
[minLength(1)]
),
publicUrl: string([url()]),
year: number()
})
),
currentSorting: object({
label: literal('новые объявления')
}),
pageCount: number()
})
It's so clean, easy to follow, add, change, etc. It can also have a different name.
Please help reduce the pain of validating such nested objects, I pray for this feature for years 🙏
You could add passthroughObject
on your own by just wrapping object
:
export function passthroughObject<TEntries extends v.ObjectEntries>(
entries: TEntries
): v.ObjectSchema<TEntries, v.UnknownSchema> {
return v.object(entries, v.unknown());
}
@fabian-hiller thank you a lot for the example, I'll use it as for now
Hopefully it can be added to core and help other developers too. I actually need it in almost every project with external API requests.
I will think about it. At the moment I prefer strong primitives over specialized functions. Also, I don't want there to be too many ways to achieve the same things within a library, because that makes usage confusing in my eyes.
The latest version now comes with a looseObject
schema 🧩
@fabian-hiller perfect, thank you! 🚀