sinclairzx81 / typebox

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

Breaking change: undefined value is not passing Type.Optional #350

Closed abuaboud closed 1 year ago

abuaboud commented 1 year ago

Today, I upgraded from version 0.24.51 to 0.26.2 and discovered a breaking change. The following TypeScript code used to pass in version 0.24.51, but now it fails in version 0.26.2.

import { Type, Static, } from '@sinclair/typebox';
import { TypeCompiler } from '@sinclair/typebox/compiler';

const optionalString = Type.Object({
  str: Type.Optional(Type.String({}))
})

const schema = TypeCompiler.Compile(optionalString);
console.log(schema.Check({
  str: undefined
}))

I am unsure if this is the intended behavior for the new version.

Thank you for this amazing library :D

sinclairzx81 commented 1 year ago

@abuaboud Hi!

Thanks for reporting. There has been some updates around undefined handling in the most recent revision inline with the exactOptionalPropertyTypes TS compiler option (which should have been documented, so it's great you've picked this up). The change was to try and make undefined checks more strict, and to make optional more associative with the presence (or absence) of object property keys.

Example

The following shows the behavior of exactOptionalPropertyTypes

TypeScript Link Here

import { Type, Static } from '@sinclair/typebox'

type T = { x?: string } // exactOptionalPropertyTypes: means "if 'x' key is present, value MUST be 'string'"

function test(value: T) { }

test({ x: undefined }) // fails

// { }              - ok:   property key 'x' missing, ok because `?` signals potential absence of property
// { x: 'hello' }   - ok:   property key 'x' exists, and is assigned type 'string'
// { x: undefined } - fail: property key 'x' exists, but is not assigned 'string'

Note, the exactOptionalPropertyTypes is not enabled by default in TypeScript (not even with strict), so I am open to easing this assertion in TypeBox (particularly if this is breaking some users). It would be possible to enable this option as a TypeSystem policy, so may consider doing this.

Let me take another look at this. Cheers! S

sinclairzx81 commented 1 year ago

@abuaboud This should be fixed on 0.26.3

If you want to use the more strict exactOptionalPropertyTypes assertion, this can be enabled using the following.

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

TypeSystem.ExactOptionalPropertyTypes = true // default is false

Let me know if this helps :) Cheers S

sinclairzx81 commented 1 year ago

@abuaboud Heya, might close this issue off as this should be resolved on 0.26.3. However, feel free to reply on this thread if you run into any problems.

Also, thanks again for reporting the issue (the undefined checks on 0.26.0 were overlooked during the revision write up, but I do think aligning to TS defaults here generally makes more sense over the ultra strict opt in assertions for exactOptionalPropertyTypes and is far less likely to cause issues for those upgrading).

All the best! S

abuaboud commented 1 year ago

Thank you @sinclairzx81 , You are awesome!