Replies: 1 comment
-
@rolanday Hi, Currently, TypeBox will internally validate the schema prior to executing the Decode. It also runs a validate after an Encode. The transform functionality was introduced on 0.31.x, but there's been a few cases where transforms are useful without validation (where the user can explicitly check themselves prior to Decode). It's noted that this case can be useful for Ajv integration cases also. A recent issue was posted about this on #631 where leveraging Ajv for validation would be the preference. CurrentThe following is the current implementation of transforms. TypeBox will internally validate the value using it's internal validation checks. import { Type, PatternNumberExact } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'
const NumericString = Type.Transform(Type.String({ pattern: PatternNumberExact }))
.Decode((value) => parseFloat(value))
.Encode((value) => value.toString())
const A = Value.Decode(NumericString, '100')
const B = Value.Encode(NumericString, 100) ProposedThe proposed solution would remove all validation checks, requiring the user to explicitly (or optionally) check the value before and after transformation. import { Type, TSchema, PatternNumberExact } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'
// ----------------------------------------------------------------------------
// Explicit Decode and Encode Validation Checks
// ----------------------------------------------------------------------------
function Decode<T extends TSchema>(schema: T, value: unknown) {
if(Value.Check(schema, value)) return Value.Decode(schema, value) // safe to decode
throw Error(Value.Errors(schema, value).First()!.message)
}
function Encode<T extends TSchema>(schema: T, value: unknown) {
const encoded = Value.Encode(schema, value)
if(!Value.Check(schema, encoded)) throw Error(Value.Errors(schema, value).First()!.message)
return encoded // encode successful
}
// ----------------------------------------------------------------------------
// Usage
// ----------------------------------------------------------------------------
const NumericString = Type.Transform(Type.String({ pattern: PatternNumberExact }))
.Decode((value) => parseFloat(value))
.Encode((value) => value.toString())
const A = Decode(NumericString, '100')
const B = Encode(NumericString, 100) Interior Transform CheckAnother usage might be push the schematic into the Decode and Encode functions, allow value checking to optionally happen within the transform itself. const NumericString = Type.Transform(Type.String({ pattern: PatternNumberExact }))
.Decode((value, schema) => {
if(Value.Check(schema, value)) return parseFloat(value) // safe to decode
throw Error(Value.Errors(schema, value).First()!.message)
})
.Encode((value, schema) => {
const encoded = value.toString()
if(!Value.Check(schema, encoded)) throw Error(Value.Errors(schema, value).First()!.message)
return encoded // encode successful
}) Open to thoughts on the above design. Note, this would be a breaking change, but do see value in making validation optional (or removed entirely). The only concern is the added complexity to the API (Transforms are already quite complicated). The "Interior Transform Check" I think would be the most ideal implementation from a user perspective, but the external implementation of Encode and Decode would be inline with the Value.* module and it's functions (where the expectation is for users to use combinations of the Value.* functions to construct their own validation pipelines) Again, open to thoughts. |
Beta Was this translation helpful? Give feedback.
-
Hello,
Is there a way to apply a transform w/ TB ahead of validation, using a single call? The sample code below is a pattern I'm familiar w/ from zod, but it doesn't apply here afaict. Also, as an aside, the error message obscures the violation reason (see error snippet below).
Thanks!
Error message (lacks schema violation details):
Beta Was this translation helpful? Give feedback.
All reactions