sinclairzx81 / typebox

Json Schema Type Builder with Static Type Resolution for TypeScript
Other
4.85k stars 155 forks source link

Is it possible to add support to the Type.String additional properties for the enum keyword #920

Closed eXigentCoder closed 3 months ago

eXigentCoder commented 3 months ago

Currently I have my string enum as:

const environment = Type.Union([
    Type.Literal('production'),
    Type.Literal('qa'),
    Type.Literal('dev'),
    Type.Literal('test'),
  ]);

But it would be more elegant if I could do this:

const environment = Type.String({ enum : ['production', 'qa', 'dev', 'test'] });

With the resulting type being:

type T = "production" | "qa" | "dev" | "test";

And the schema being:

const T = {
  type : "string",
  enum : ['production', 'qa', 'dev', 'test'] 
}  

I know I could also achieve something similar with using the Enum, but both the Enum and Union + Literal JSON schemas are a lot more complex to process as they utilise anyOf

sinclairzx81 commented 3 months ago

@eXigentCoder Hi,

TypeBox does't generate enum schematics....currently. Instead it preferences anyOf because this keyword generalizes to all types, (not limited to string, number, boolean, etc), and also means TypeBox can maintain a singular code path for inferring and processing unions (where enum would introduce a secondary path).

This said, I am looking into supporting the enum string representation, but it's not going to be ready for some time. The work involves implementing a infrastructure to remap Enum into Union when attempting to apply type transforms and composition, of which attempts to introduce this under the current infrastructure would be untenable given the complexity of unions.


StringEnum

Even though TypeBox doesn't generate these schematics, you can write a custom type that does. The following is one way to approach it.

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

const StringEnum = <T extends string[]>(items: [...T]) => 
  Type.Unsafe<T[number]>({ type: 'string', enum: items })

// ...

const T = StringEnum(['A', 'B', 'C'])

type T = Static<typeof T>

If using the TypeCompiler / Value modules to validate this type, have a read over the TypeRegistry section of the readme as you will need to register for schematics of this form.

https://github.com/sinclairzx81/typebox#typeregistry

Hope this helps S

eXigentCoder commented 3 months ago

Hey there, Thanks so much for the feedback, makes a lot of sense and thank you for a really awesome library!

gotenxds commented 3 weeks ago

Hi @sinclairzx81, is there any update on this or an open issue we can fallow?

sinclairzx81 commented 3 weeks ago

@gotenxds Hi,

is there any update on this or an open issue

Unfortunately not at the moment. This said, I am currently working on the next significant revision for TypeBox from now and through to the end of the year; and of which, there are plans to have Type.Enum(['A', 'B']) generate { enum: ['A', 'B'] } representations in that revision (which has involved a fairly significant revamp of TypeBox's type infrastructure)

I don't have much to share at this stage, and this work is being kept under private repository for the time being. The next revision is effectively a rewrite of the Type.* namespace and will take a few months to complete. I am hoping to have this revision ready December 2024/January 2025, so if you check back then I may have more to share.

Cheers S