elysiajs / elysia

Ergonomic Framework for Humans
https://elysiajs.com
MIT License
10.35k stars 220 forks source link

TypeBox support with working types #75

Closed itsyoboieltr closed 1 month ago

itsyoboieltr commented 1 year ago

It would be nice if we could use TypeBox functionalities with Elysia t in a type safe manner. The issue is was already mentioned in #66: Property '[Kind]' is missing in type 'TObject<{}>' but required in type 'TSchema'.ts(2345) Elysia types do work with TypeBox, but the types need to be casted to avoid typescript errors. I wonder if this could be fixed someway, to have proper typing. Reproduction + my current (kind of boring and annoying) workaround:

import { t, UnwrapSchema } from 'elysia';
import { Value } from '@sinclair/typebox/value';

const test = t.String({ default: 'test' });

const testValue = Value.Create(test);

// Argument of type 'TString' is not assignable to parameter of type 'TSchema'. Property '[Kind]' is missing in type 'TString' but required in type 'TSchema'. ts(2345)

// but this is only a type error, the function still works.

const testValueFixed: UnwrapSchema<typeof test> = Value.Create(test as any);

// type error workaround
SaltyAom commented 1 year ago

Does #66 work for you?

Elysia.t is built on TypeBox but it does some type override which might cause Symbol to be misunderstood by TypeScript itself, basically you should be able to use it despite the warning.

However, I'd recommended using TypeCompiler instead of Value for AoT compilation, you should be able to do either:

Using TypeBox Compiler

import { t } from 'elysia'
import { TypeCompiler } from '@sinclair/typebox/compiler'

const valueToCheck = {}

const a = TypeCompiler.Compile(
  t.Object({
      username: t.String()
  })
)

if(a?.Check(valueToCheck))
 console.log(a?.Errors(valueToCheck))

If TypeBox Compiler cause and error, you could use getSchemaValidator from Elysia, this should fix the type error.

import { t, getSchemaValidator } from 'elysia'

const a = getSchemaValidator(
  t.Object({
      username: t.String()
  }),
       // This is a reference model to resolve, aka. Elysia.model
       // Use to resolve named schema
  {}
)

const valueToCheck = {}

if(a?.Check(valueToCheck))
 console.log(a?.Errors(valueToCheck))

Let me know if this help!

itsyoboieltr commented 1 year ago

This works:

const a = getSchemaValidator(
  t.Object({
    username: t.String()
  }),
       // This is a reference model to resolve, aka. Elysia.model
       // Use to resolve named schema
  {}
)

This does not work:

const a = TypeCompiler.Compile(
  t.Object({
    username: t.String()
  })
)

And the feature request is, is there any way to fix the type error when using the native TypeBox functions, by adding the Property '[Kind]', which is required in TSchema? to avoid the error mentioned before.

KryptXBSA commented 1 year ago

Not sure if this helps, but you can extract the Static type from a schema via <schema>.static:

import { t } from "elysia";
import { Static } from "@sinclair/typebox";

const testSchema = t.String({ default: "test" });

// Type 'TString' does not satisfy the constraint 'TSchema'. Property '[Kind]' is missing in type 'TString' but required in type 'TSchema'. 
type TestSchema = Static<typeof testSchema>     

// TestSchema is of type string
type TestSchema = typeof testSchema.static;
MeowningMaster commented 8 months ago

Typebox didn't hit v1 yet and have many breaking changes in each release. The fix is to synchronize typebox version with elysia's. Actually i don't put @synclair/typebox to my package.json at all, I can do it because bun (and pnpm) hoists dependencies in node_modules

schema.ts image controller.ts image

SaltyAom commented 1 month ago

Elysia installed with a specific version of Typebox. If you install TypeBox separately a version is going to mismatch.

To fix this, we can add a override fields in package.json to synchronize both version of TypeBox.

{
    "override": {
        "@sinclair/typebox": "0.32.4"
    }
}

Feels free to reopen the issue if this doesn't help.