Skip to content
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

new ts 5.0 const generic enum? #367

Closed
trim21 opened this issue Mar 31, 2023 · 5 comments
Closed

new ts 5.0 const generic enum? #367

trim21 opened this issue Mar 31, 2023 · 5 comments
Labels
future Candidate future functionality

Comments

@trim21
Copy link

trim21 commented Mar 31, 2023

ts 5.0 new feature const generic type microsoft/TypeScript#51865

Type.Enum(
      {
        s3: 's3',
        FS: 'fs',
      } as const,
      { default: 'fs },
    )

could become

Type.Enum(
      {
        s3: 's3',
        FS: 'fs',
      } ,
      { default: 'fs' },
    )

without as const

@sinclairzx81
Copy link
Owner

sinclairzx81 commented Mar 31, 2023

@trim21 Hi, thanks for the suggestion :)

At this stage, I'm holding off on const generics to ensure backwards compat for TS 4.2.3, but will review places where const generics would be applicable in later revisions of the library (likely when TS 5.0 has been around for a few months). For now, the following is still the recommended way to express Type.Enum; using an auxiliary enum structure (or alternatively a literal union)

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

enum Foo { A, B, C }

const T = Type.Enum(Foo)

function test(value: Static<typeof T>) {
    switch(value) {
        case Foo.A: return console.log('Foo.A')
        case Foo.B: return console.log('Foo.B')
        case Foo.C: return console.log('Foo.C')
    }
}

test(Foo.A)
test(Foo.B)
test(Foo.C)

Btw, Is the explicit expression of { s3: 's3', FS: 'fs' } a common way to express enums over using the language supported enum?. I remember hearing something about explicitly specifying enums the way you have being a preference for some developers, but can't remember the details / rationales as to why.

Anyway, hope this brings some insights into the future plans for const generics in TB
S

@trim21
Copy link
Author

trim21 commented Mar 31, 2023

Btw, Is the explicit expression of { s3: 's3', FS: 'fs' } a common way to express enums over using the language supported enum?

It's used in a object as options, so I just write a inline enum. So I don't need to create a ts enum.

I'm actually using it as a union, so I don't need to write this:

t.Union(
      [
        t.Literal('s3'),
        t.Literal('fs'),
      ],
      { default: 'fs' },
    )

@sinclairzx81
Copy link
Owner

I'm actually using it as a union, so I don't need to write this:

I mean as opposed to this (using an enum with string values)

enum StorageOptionEnum {
    s3 = 's3',
    fs = 'fs'
}

const StorageOption = Type.Enum(StorageOptionEnum) // const StorageOption = { // produces a union structure
                                                   //   anyOf: [
                                                   //     { type: 'string', const: 's3' },
                                                   //     { type: 'string', const: 'fs' } 
                                                   //   ]
                                                   // }

function store(value: Static<typeof StorageOption>) {
    switch(value) {
      case StorageOption.s3: return console.log('StorageOption.s3')
      case StorageOption.fs: return console.log('StorageOption.fs')
    }
}

store(StorageOption.s3)
store(StorageOption.fs)

Side note, I see that TS 5.0 actually treats all enums as unions now, wondering if TypeBox should yield infer union (as opposed to the original enum). May take a closer look at this.

@trim21
Copy link
Author

trim21 commented Mar 31, 2023

Yes I know, I just don't want to write a seprated ts Enum 😆 I write literial value in case.

It already yield infer union I think? I try console.log(t.Enum) and it's a union kind.

@sinclairzx81
Copy link
Owner

Ah, yeah, I guess it would infer a union with as const :) Have just been tinkering with the const generics on enum TypeScript Link Here

// ------------------------------------------------------------------
// Enum Inference
// ------------------------------------------------------------------
type Evaluate<T> = T extends infer O ? { [K in keyof O]: O[K] } : never
type EnumLike = Record<string, string | number>
type EnumStatic<T extends EnumLike> = Evaluate<T[keyof T]>
declare function Enum<const T extends EnumLike>(value: T): EnumStatic<T>


// ------------------------------------------------------------------
// Example
// ------------------------------------------------------------------
enum StorageOptionEnum {
    s3 = 's3',
    fs = 'fs'
}

const A = Enum(StorageOptionEnum)  // A is StorageOptionEnum
const B = Enum({ a: '1', b: '2' }) // B is '1' | '2'

It's all good on the TS 5 front, but breaking on versions prior. I'm not sure what the compiler would do if importing declarations using const generics on older versions (maybe it's clever enough to ignore the const on the generic argument?). I think for now, will need to keep on with the explicit as const. TypeBox tries to support compiler versions back as early as 4.1.5 (and only recently got bumped to 4.2.3 on 0.26.0), but may re-assess this over the course of the 0.26.0, will keep an eye on the uptake of TS 5 and make a call down the road (I like the newer features too!)

Thanks against for the suggestion, will close off this one for now as updates are not likely for at least several months, but will revisit this issue at a later time.

All the best!
S

@sinclairzx81 sinclairzx81 added the future Candidate future functionality label Mar 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
future Candidate future functionality
Projects
None yet
Development

No branches or pull requests

2 participants