sinclairzx81 / typebox

Json Schema Type Builder with Static Type Resolution for TypeScript
Other
4.78k stars 152 forks source link

Type.Optional with Type.Transform unexpected behaviour #958

Closed schusj closed 4 weeks ago

schusj commented 4 weeks ago

The following fails as it is passing undefined to the transform and creating an invalid time value. I would expect it to never hit the Transform code as the optional allows an undefined key.

const T = Type.Object({
  optionalDate: Type.Optional(
    Type.Transform(Type.RegExp(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})/))
      .Decode(value => new Date(value))
      .Encode(value => value.toISOString()),
  ),
});

const parsed = Value.Parse(T, {});

is this the wrong way to do something like this?

sinclairzx81 commented 4 weeks ago

@schusj Hiya, Thanks for reporting, this was a good catch.

I have published a fix for this on 0.33.5. The following should now work as expected. Note, I've updated the regex in your example to match the toISOString() return format, you may want to use this version if you want formats to be symmetric on Encode and Decode.

import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'

const DateType = Type.Transform(Type.RegExp(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/))
  .Decode((value) => new Date(value))
  .Encode((value) => value.toISOString())

const T = Type.Object({
  optionalDate: Type.Optional(DateType),
})

// Default

const A = Value.Parse(T, { optionalDate: new Date().toISOString() }) // { optionalDate: 2024-08-14T06:04:05.717Z }

const B = Value.Parse(T, { optionalDate: undefined })                // { optionalDate: undefined }

const C = Value.Parse(T, { })                                        // { }

// Optional: Use to align TypeBox with exactOptionalPropertyTypes tsconfig option

import { TypeSystemPolicy } from '@sinclair/typebox/system'

TypeSystemPolicy.ExactOptionalPropertyTypes = true

const D = Value.Parse(T, { optionalDate: undefined })                // throws AssertError: Expected string

Thanks again S