fix(experimental): allow partial object defaults with optional - #198
Conversation
Parent `v.object(..., { optional: true, default: {} })` no longer requires
every nested field to be listed in the default. Also expose `optional` on
base type options so helpers like `v.number({ optional: true })` accept it
cleanly.
commit: |
|
| * fine at the type level - parent `optional` / `default` must not | ||
| * demand that every required child be listed in the default. | ||
| */ | ||
| type ObjectDefault<S> = DefaultInput<Partial<ArgsShape<S>>>; |
There was a problem hiding this comment.
Partial defaults fail validation
When a partial object default omits a required child without its own default, the new type accepts the declaration, but runtime validation checks that child as undefined, causing validation to throw instead of returning the declared object output.
Knowledge Base Used: Validation and schema contracts
|
|
||
| export type TypeOptions<T, O> = { | ||
| transform?: (value: T) => O; | ||
| /** Accepted on every helper; overloads refine the output when `true`. */ |
There was a problem hiding this comment.
Dynamic optional flags misinfer output
When a caller passes a non-literal boolean such as v.number({ optional: condition }) and its value is true, the fallback overload infers a non-optional output while runtime validation returns undefined, allowing downstream code to use an absent value as an unconditional primitive.
Summary
v.object(shape, { optional: true, default: {} })was failing whenever the shape had required fields, and TypeScript blamedoptionaleven though the real mismatch was the empty default. Object defaults are now typed as partial inputs, so a parent being optional/defaulted does not force every child to appear in the default.Also put
optionalon the shared type options so helpers likev.number({ optional: true })accept it without falling through to an overload that pretends the property does not exist.