Comments (5)
@pterrien Hiya,
I guess a workaround for me would be to build an "empty" initial value, depending on the base type of my schema, something like:
Yeah, while possible, this is somewhat working against the grain. While the Default function is written to generate values users may have missed, there is still potential for values to be invalid, and there's a line between what can be reasonably generated and what users "should" pass for an value to be considered valid. For example, if a user passes undefined
instead of an object, and the validator simply constructs an object, was there any reason for the user to pass anything at all?
This said, you can control what gets generated by setting default annotations at each level of the type.
import { Type } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'
const T = Type.Object({
vector: Type.Object({
x: Type.Number({ default: 1 }),
y: Type.Number({ default: 2 }),
z: Type.Number({ default: 3 }),
}, { default: {} }),
normal: Type.Object({
x: Type.Number({ default: 1 }),
y: Type.Number({ default: 2 }),
z: Type.Number({ default: 3 }),
}, { default: {} })
}, { default: {} })
const R = Value.Default(T, undefined)
console.log(R) // { vector: { x: 1, y: 2, z: 3 }, normal: { x: 1, y: 2, z: 3 } }
TypeBox will generate values at each level level, expanding out to the complete value. By omitting a default annotation at a higher level, this will prevent Default from initializing a value (and may result in error on decode if the user hasn't provided correct sub values (which is a good thing)). The rules around how applications want to approach value initialization are very nuanced, and TypeBox can't really assume anything, but you should be able to get some use out of Default based on the above.
Additionally, user defined Value functions (implemented entirely outside of Value.* using schema introspection) are encouraged, so if you do need something specific, you can implement functions from scratch (just check the way TB implements the current Value.* functions for an example on how to approach that (most are written using visitor patterns))
Again, hope this helps!
S
from typebox.
@pterrien Hi,
Question: Is there a way to not apply these implicit defaults? Something like a Value.CreateStrict(), that would ultimately fail on Value.Decode(), similarly to Value.Default()?
The Create function is intended to instantiate a value that matches the given type, so it does need to initialize implicit defaults. The same is true for Cast. Keep in mind that Create and Cast are usually not very helpful for validation (they are more intended for data migration scenarios where you may need to instance (and fix) values due to schematic changes; this is particularly true for Cast)
The Default function however is intended for use in validation so would recommend using this if the goal is to validate. The Default function can pre-process a value prior to validation (Decode) by applying defaults for any default
annotated type,; a lot of server frameworks use it for this purpose. The function actually replicates the Ajv useDefaults
https://ajv.js.org/options.html#usedefaults configuration if you're familiar with it.
Um, I'm not too sure what to suggest here except perhaps consider avoiding Create, Cast during validation passes (as Default, Clean and Convert are typically the functions to use for pre-processing values). Any additional processing above Default, Clean and Convert would likely need to be custom....
export function Parse<T extends TSchema>(schema: T, value: unknown) {
const converted = Value.Convert(T, value)
const defaulted = Value.Default(T, converted)
const cleaned = Value.Clean(T, defaulted)
// todo: additional custom processing of the value here.
return Value.Decode(schema, cleaned)
}
The above is the intended usage for these functions and will error if the value is incorrect by the time it reaches the Decode call. It should be possible to apply custom logic prior to the Decode call if you need it.
Hope this helps
S
from typebox.
Hi,
Thank you for your very quick reply.
I actually use the Parse()
function, that I copied from issue #726 . I restricted my example code to Value.Decode(T, Value.Default(T, value))
, just for the sake of clarity.
My problem being that, if I pass an undefined
value to it, the error message is simply 'Expected object', because undefined
will not get coerced to an Object.
I guess a workaround for me would be to build an "empty" initial value, depending on the base type of my schema, something like:
let initValue
if (
Type.Extends(T, Type.Object({}), Type.Literal(true), Type.Literal(false)).const
) {
initValue = {}
} else if (
Type.Extends(T, Type.Array(Type.Unknown()), Type.Literal(true), Type.Literal(false)).const
) {
initValue = []
} else {
initValue = undefined
}
const invalid3 = Parse(T, initValue) // correctly throws an error, with message='Required property` and path='/per'
Not the most elegant, and surely not bullet-proof with exotic schemas (intersect, union, ...), but in my use case I guess it should be acceptable as long as I use fairly standard schemas.
from typebox.
TypeBox can't really assume anything, but you should be able to get some use out of Default based on the above.
This totally makes sense, and using default
on the object is indeed far more rigorous and elegant than my ugly workaround... :)
if you do need something specific, you can implement functions from scratch (just check the way TB implements the current Value.* functions for an example on how to approach that (most are written using visitor patterns))
I will definitely have a look, even though using default
will probably cover my needs.
Again, hope this helps!
A lot, I sincerely thank you for your kind help!
from typebox.
@pterrien All good :)
Will go ahead and close up this issue for now.
All the best!
S
from typebox.
Related Issues (20)
- Migrate to regexp vs string type in pattern HOT 4
- feedback on Refinement API HOT 2
- Type.Date() cause errors with fastify and querybuilder returning type Date HOT 2
- Should coerce type to array HOT 2
- Interconnected interfaces, missing type annotations and maximum length exceeded. HOT 2
- Optimisations to inference in 0.32 seems to cause `ts(2589)` with composite types. HOT 16
- Add trim option to Type.String() HOT 1
- Should add option to remove redundant prop in Convert() HOT 1
- Metadata missing in custom types HOT 2
- Schema of JSON Schema HOT 3
- Utility type inference appears missing or broken HOT 2
- How to express function optional parameter? HOT 5
- Clean call on extended prisma result object does not work HOT 2
- esm.sh builds are broken if using FormatRegistry HOT 1
- Circular references HOT 4
- Value.Clean causes dereference error on Recursive type with nullable optional union HOT 2
- How to work with dates and timestamps HOT 2
- Issue regarding enums becoming never when using a partial deep method HOT 2
- Support for composite custom kinds HOT 1
- transform object property encoding HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typebox.