-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fails with oneOf
#16
Comments
@xddq Heya, You can emit for the import { Type, Static, TSchema, TUnion, SchemaOptions } from '@sinclair/typebox'
// -------------------------------------------------------------------------------------------------
// If the schema contains 'oneOf`, it's possible to emit this support type using Type.Unsafe. Just
// be mindful that the TypeCompiler does not support `oneOf`, so the following definition is only
// useful when Ajv is used for validation.
// -------------------------------------------------------------------------------------------------
const OneOf = <T extends TSchema[]>(oneOf: [...T], options: SchemaOptions = {}) =>
Type.Unsafe<Static<TUnion<T>>>({ ... options, oneOf })
const T = Type.Object({
x: OneOf([Type.String(), Type.Number(), Type.Boolean()])
})
type T = Static<typeof T> Similar techniques can be used to emit for import { Type, Static, SchemaOptions } from '@sinclair/typebox'
const StringEnum = <const T extends string[]>(values: [...T], options: SchemaOptions = {}) =>
Type.Unsafe<T[number]>({ ... options, enum: values })
const T = Type.Object({
x: StringEnum(['A', 'B', 'C'])
})
type T = Static<typeof T> It should be possible to handle many non-mappable schemas by emitting these support types at the top of the generated output. Additionally, there are actually ways to get these working with the TypeCompiler, but you might want to put custom type setup behind a CLI flag. Let me know if you want some info on how to do that. Hope this helps! |
@xddq Actually, just for completeness and reference, the following includes the registry setup to support import { Type, Kind, TypeRegistry, Static, TSchema, TUnion, SchemaOptions } from '@sinclair/typebox'
// --------------------------------------------------------------------
// Registry
// --------------------------------------------------------------------
TypeRegistry.Set('StringEnum', (schema: any, value) => schema.enum.includes(value))
TypeRegistry.Set('OneOf', (schema: any, value) => 1 === schema.oneOf.reduce((acc: number, schema: any) => acc + (Value.Check(schema, value) ? 1 : 0), 0))
// --------------------------------------------------------------------
// Support Types
// --------------------------------------------------------------------
const StringEnum = <T extends string[]>(enum_: [...T], options: SchemaOptions = {}) => Type.Unsafe<T[number]>({ ... options, [Kind]: 'StringEnum', enum: enum_ })
const OneOf = <T extends TSchema[]>(oneOf: [...T], options: SchemaOptions = {}) => Type.Unsafe<Static<TUnion<T>>>({ ...options, [Kind]: 'OneOf', oneOf })
// --------------------------------------------------------------------
// Example
// --------------------------------------------------------------------
import { Value } from '@sinclair/typebox/value'
const T = Type.Object({
x: OneOf([Type.String(), Type.Number(), Type.Boolean()]),
y: StringEnum(['A', 'B', 'C'])
})
type T = Static<typeof T>
console.log(Value.Check(T, { x: 42, y: 'B' })) // true Cheers |
@sinclairzx81 With your consistently speedy, thorough and well-written responses to issues I am curious when you find the time to sleep! |
@jessekrubin Hey! Thanks for raising the issue! Would be cool to provide additional information the next time to reduce time spent on issues and PRs. Was my bad, I did now decide to simply create an issue template for the future ones. I got some questions. I am actually quite bad at json schema so bare with me :p
@sinclairzx81 Hey! thanks for hopping in and your responses! I am curious.. Your implementation for oneOf seems to be pretty straight forward.
|
Ack! Sorry! I have been in your shoes many a time! I was fried yesterday when I made the bug. I was trying to auto-generate a type-box definition for this schema: https://proj.org/en/9.2/schemas/v0.6/projjson.schema.json |
@xddq I think that there are technically key-differences with one-of vs any-of in that a piece of data should really only validate successfully against one as opposed to multiple(?) but I am not sure. |
@jessekrubin no worries. Thanks for the example! Yeah, the swagger/openapi page actually give a good rundown with examples for oneOf which made me somewhat understand its use. src Will probably wait for update from sinclair for next steps |
@xddq Hi
The type T = string | string // This type is fine (assert for string)
const T = Type.AnyOf([Type.String(), Type.String()]) // This schema is fine (assert for string)
const T = Type.OneOf([Type.String(), Type.String()]) // This schema is illogical (will always fail) For TypeBox to handle certain compositions (Enum, KeyOf, Conditional Types, TemplateLiterals, Indexers, etc), it also needs to be able to pivot around a singular schema representation describing union types. The
Yes, the following will make the TypeRegistry.Set('OneOf', (schema: any, value) => {
return 1 === schema.oneOf.reduce((acc: number, schema: any) => acc + (Value.Check(schema, value) ? 1 : 0), 0)
}) Note: The TypeCompiler cannot generate optimized code for custom types (currently). Instead, the compiled output will call out to a
Yeah, you could implicitly rewrite Hope this helps! |
@sinclairzx81 again, fantastic detailed response! I think I noticed you have a oneOf thingy in typebox's PS: I just cleaned-up/published/made-public this thing I have been using for a while (https://github.com/jessekrubin/geobox) and was curious to know what you all think (if you have a spare minute to take a look). |
@jessekrubin mhh, looks interesting but I think that it lacks documentation. I did not really understand the use case and usage by going through the readme. Closing this for now since a PR was created here. Will probably be released as 1.2.0. |
@xddq thanks for the feed back! Totally agree. I didn't really add much of any documentation (yet!). Use case (if you are curious) is custom geo (right now geojson) schemas where you can set the schema for the I just put it (the package) out there quickly to show you and @sinclairzx81 for some feedback. PS: I work in the world of geo-sciences. |
@xddq did you ever look at forking https://github.com/StefanTerdell/json-schema-to-zod? |
@jessekrubin I will keep it in the back of my head if I get to do stuff with geo-json. Did not to do much with it yet. I did not look at forking json-schema-to-zod, no. However after going over it, it looks like I should be using json-schema-ref-parser for $ref resolution :] If there is anything, please jump to the discussions or create a new issue. |
## Summary Implements oneOf support for schema2typebox. More info [here](#16)
get
Error: JSON schema had invalid value for 'type' attribute. Got: undefined
The text was updated successfully, but these errors were encountered: