sinclairzx81 / typebox

Json Schema Type Builder with Static Type Resolution for TypeScript
Other
4.79k stars 153 forks source link

Date type generation error #281

Closed itpropro closed 1 year ago

itpropro commented 1 year ago

Why is the Type.Date type generated as object type? This is a generated schema by typebox:

// Schema object
Type.Object({
    dateType: Type.Date(),
  })

// Generated schema
{
  type: 'object',
  properties: {
    dateType: {
      type: 'object',
      instanceOf: 'Date',
      [Symbol(TypeBox.Kind)]: 'Date'
    },
  },
  required: [ 'dateType' ],
  [Symbol(TypeBox.Kind)]: 'Object'
}

Regarding to the ajv documentation, the date or date-time format should be implemented like this in the schema:

const schema = {
  type: "string",
  format: "date",
  formatMinimum: "2016-02-06",
  formatExclusiveMaximum: "2016-12-27",
}

With the above generated schema, I always get the 'dateType' property type must be object error, but it should be a string and not an object from my understanding.

This manual implementation (which I would expect to be generated by the Type.Date type) works:

// Schema object
Type.Object({
    dateCustom: Type.Unsafe<{customDate: Date}>({
      type: 'object',
      properties: {
        customDate: {
          type: 'string',
          format: 'date-time'
        }
      },
      required: [
        'customDate'
      ],
      additionalProperties: false
    })
  })

// Generated schema
{
  type: 'object',
  properties: {
    dateCustom: {
      type: 'object',
      properties: { customDate: { type: 'string', format: 'date-time' } },
      required: [Array],
      additionalProperties: false,
      [Symbol(TypeBox.Kind)]: 'Unsafe'
    }
  },
  required: [ 'dateCustom' ],
  [Symbol(TypeBox.Kind)]: 'Object'
}
sinclairzx81 commented 1 year ago

Hi,

Why is the Type.Date type generated as object type?

typeof new Date() // 'object'

Regarding to the ajv documentation, the date or date-time format should be implemented like this in the schema:

You will need to use the unsafe type you've specified above as TypeBox does not implement the Ajv string representation or value coercion rules for Date objects. In TypeBox, Type.Date() is intended to validate specifically against a JavaScript Date object only, not the iso-8601 representation (as in the Ajv case).

For Iso-8601 date strings without value coercion, you would express them as strings with one of the following formats (and require the ajv-formats package)

const T = Type.String({ format: 'date-time' }) // where T is string
const T = Type.String({ format: 'date' }) 
const T = Type.String({ format: 'time' })

For validators that provide library specific Date functionality, the ability to express the required schema representation is offered by way of unsafe types.

For more information on configuring Ajv for the Type.Date() type, see the Extended Ajv Configuration section for Extended Types here.

Dates and Serialization

As Date objects cannot be object serialized to JSON and are not formally recognized by the JSON Schema specification, TypeBox only provides the Date type as an extended non-standard type for use in applications that may opt to use serializers that support Date object serialization (such as msgpack)

TypeBox treats validation and message encoding as distinct concerns. So if receiving a Type.Date() value from over the network, this would require the Date value to be decoded as a Date object first before being passed to the validator.

Hope this helps!

itpropro commented 1 year ago

You will need to use the unsafe type you've specified above as TypeBox does not implement the Ajv string representation or >value coercion rules for Date objects. In TypeBox, Type.Date() is intended to validate specifically against a JavaScript Date >object only, not the iso-8601 representation (as in the Ajv case).

For Iso-8601 date strings without value coercion, you would express them as strings with one of the following formats (and >require the ajv-formats package)

That makes sense, thanks a lot for explaining! I thought the Type.Date() implementation would be some kind or shortcut for string with format: 'date/date-time' in the background.

vjau commented 1 year ago

Would it please be possible to get the Value.Cast function to parse strings to Type.Date object ? Actually it seems to be generating new Date(0)

sinclairzx81 commented 1 year ago

@vjau Hi. Date conversion for Value.Cast has been implemented on 0.25.18. The relevant PR for this can be found https://github.com/sinclairzx81/typebox/pull/307. It should support both numeric (timestamp) and iso8601 strings (and a few variants of).

If you spot any problems or have any suggestions, please feel free to submit an issue. Cheers S