Description
Currently, if we use the spread operator (...
) to merge objects as shown below, it causes side effects and cannot be tree-shaken:
const ParentSchema = v.object({
foo: v.string(),
});
const LoginSchema = v.object({
...ParentSchema.entries, // <- side effect
email: v.pipe(v.string(), v.email()),
password: v.pipe(v.string(), v.minLength(8)),
});
Playground
https://stackblitz.com/edit/node-gq8gcqea?file=index.js
The reason is that bundlers like Rollup set propertyReadSideEffects
to true
by default, which means the spread operator is treated as a side effect.
We can set the treeshake.preset
to "smallest"
to disable propertyReadSideEffects
and make it tree-shakeable but this may cause other issues.
Solution
I wonder if we could have a v.merge
function with a @__NO_SIDE_EFFECTS__
annotation for merging objects, making it possible for bundlers to tree-shake it:
// @__NO_SIDE_EFFECTS__
function merge(a, b) {
return v.object({
...a.entries,
...b.entries,
});
}
Usage
const ParentSchema = v.object({
foo: v.string(),
});
const LoginSchema = v.merge(
ParentSchema,
v.object({
email: v.pipe(v.string(), v.email()),
password: v.pipe(v.string(), v.minLength(8)),
})
);
It would be even better if the v.merge
function supported an unlimited number of arguments to merge multiple objects at once.
Alternative: Supports input array in v.object
Also, I am wondering if we can support input an array of entries
in v.object
, like:
// @__NO_SIDE_EFFECTS__
function object(entries, message) {
if (Array.isArray(entries)) {
return v.object(
entries.reduce((acc, current) => ({ ...acc, ...current }), {}),
message
);
}
// ... original implementation
}
Usage
const ParentSchema = v.object({
foo: v.string(),
});
const LoginSchema = v.object([
ParentSchema.entries,
{
email: v.pipe(v.string(), v.email()),
password: v.pipe(v.string(), v.minLength(8)),
}
]);
It can also be tree-shaken as the spread operator is not used.
Thanks @antfu for helping clarify this issue.